go-ethereum/consensus/XDPoS/engines/engine_v1/utils.go
Daniel Liu ad0eea0f07
refactor(crypto): vendor in golang.org/x/crypto/sha3 #33323 (#2046)
The upstream libray has removed the assembly-based implementation of
keccak. We need to maintain our own library to avoid a peformance
regression.

---------

Co-authored-by: Felix Lange <fjl@twurst.com>
Co-authored-by: lightclient <lightclient@protonmail.com>
2026-02-28 17:23:57 +04:00

116 lines
3.7 KiB
Go

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/crypto/keccak"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
// 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, err := utils.ExtractValidatorsFromBytes(checkpointHeader.Validators)
if err != nil {
return map[common.Address]common.Address{}, err
}
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 := keccak.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)
}
if err := rlp.Encode(hasher, enc); err != nil {
panic("rlp.Encode fail: " + err.Error())
}
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
}