package engine_v1 import ( "errors" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/rlp" "golang.org/x/crypto/sha3" ) // Get masternodes address from checkpoint Header. func decodeMasternodesFromHeaderExtra(checkpointHeader *types.Header) []common.Address { masternodes := make([]common.Address, (len(checkpointHeader.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength) for i := 0; i < len(masternodes); i++ { copy(masternodes[i][:], checkpointHeader.Extra[utils.ExtraVanity+i*common.AddressLength:]) } return masternodes } // Get m2 list from checkpoint block. func getM1M2FromCheckpointHeader(checkpointHeader *types.Header, currentHeader *types.Header, config *params.ChainConfig) (map[common.Address]common.Address, error) { if checkpointHeader.Number.Uint64()%common.EpocBlockRandomize != 0 { return nil, errors.New("this block is not checkpoint block") } // Get signers from this block. masternodes := decodeMasternodesFromHeaderExtra(checkpointHeader) validators := utils.ExtractValidatorsFromBytes(checkpointHeader.Validators) m1m2, _, err := getM1M2(masternodes, validators, currentHeader, config) if err != nil { return map[common.Address]common.Address{}, err } return m1m2, nil } func getM1M2(masternodes []common.Address, validators []int64, currentHeader *types.Header, config *params.ChainConfig) (map[common.Address]common.Address, uint64, error) { m1m2 := map[common.Address]common.Address{} maxMNs := len(masternodes) moveM2 := uint64(0) if len(validators) < maxMNs { return nil, moveM2, errors.New("len(m2) is less than len(m1)") } if maxMNs > 0 { isForked := config.IsTIPRandomize(currentHeader.Number) if isForked { moveM2 = ((currentHeader.Number.Uint64() % config.XDPoS.Epoch) / uint64(maxMNs)) % uint64(maxMNs) } for i, m1 := range masternodes { m2Index := uint64(validators[i] % int64(maxMNs)) m2Index = (m2Index + moveM2) % uint64(maxMNs) m1m2[m1] = masternodes[m2Index] } } return m1m2, moveM2, nil } func sigHash(header *types.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() enc := []interface{}{ header.ParentHash, header.UncleHash, header.Coinbase, header.Root, header.TxHash, header.ReceiptHash, header.Bloom, header.Difficulty, header.Number, header.GasLimit, header.GasUsed, header.Time, header.Extra[:len(header.Extra)-crypto.SignatureLength], // Yes, this will panic if extra is too short header.MixDigest, header.Nonce, } if header.BaseFee != nil { enc = append(enc, header.BaseFee) } rlp.Encode(hasher, enc) hasher.Sum(hash[:0]) return hash } // ecrecover extracts the Ethereum account address from a signed header. func ecrecover(header *types.Header, sigcache *utils.SigLRU) (common.Address, error) { // If the signature's already cached, return that hash := header.Hash() if address, known := sigcache.Get(hash); known { return address, nil } // Retrieve the signature from the header extra-data if len(header.Extra) < utils.ExtraSeal { return common.Address{}, utils.ErrMissingSignature } signature := header.Extra[len(header.Extra)-utils.ExtraSeal:] // Recover the public key and the Ethereum address pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature) if err != nil { return common.Address{}, err } var signer common.Address copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) sigcache.Add(hash, signer) return signer, nil }