mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-20 13:44:31 +00:00
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>
116 lines
3.7 KiB
Go
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
|
|
}
|