mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-24 23:46:17 +00:00
Xin 113 is epoch switch (#37)
* add isEpochSwitch function and refactor utils * fix broken first v2 epoch switch block * use adaptor epoch switch function to determine v1 v2 epoch swtich block * add test for the GetMasternodesByNumber and GetCurrentEpochSwitchBlock function * add v2 test for isAuthroisedAddress * Use GetCurrentEpochSwitchBlock in findNearestSignedBlock api
This commit is contained in:
parent
3ac908be8d
commit
f8d3f9f8c6
21 changed files with 589 additions and 349 deletions
|
|
@ -35,8 +35,13 @@ import (
|
|||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
func SigHash(header *types.Header) (hash common.Hash) {
|
||||
return utils.SigHash(header)
|
||||
func (x *XDPoS) SigHash(header *types.Header) (hash common.Hash) {
|
||||
switch x.config.BlockConsensusVersion(header.Number) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
return x.EngineV2.SignHash(header)
|
||||
default: // Default "v1"
|
||||
return x.EngineV1.SigHash(header)
|
||||
}
|
||||
}
|
||||
|
||||
// XDPoS is the delegated-proof-of-stake consensus engine proposed to support the
|
||||
|
|
@ -240,12 +245,12 @@ func (x *XDPoS) GetPeriod() uint64 {
|
|||
return x.config.Period
|
||||
}
|
||||
|
||||
func (x *XDPoS) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool {
|
||||
func (x *XDPoS) IsAuthorisedAddress(chain consensus.ChainReader, header *types.Header, address common.Address) bool {
|
||||
switch x.config.BlockConsensusVersion(header.Number) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
return x.EngineV2.IsAuthorisedAddress(header, chain, address)
|
||||
return x.EngineV2.IsAuthorisedAddress(chain, header, address)
|
||||
default: // Default "v1"
|
||||
return x.EngineV1.IsAuthorisedAddress(header, chain, address)
|
||||
return x.EngineV1.IsAuthorisedAddress(chain, header, address)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,6 +263,20 @@ func (x *XDPoS) GetMasternodes(chain consensus.ChainReader, header *types.Header
|
|||
}
|
||||
}
|
||||
|
||||
func (x *XDPoS) GetMasternodesByNumber(chain consensus.ChainReader, blockNumber uint64) []common.Address {
|
||||
blockHeader := chain.GetHeaderByNumber(blockNumber)
|
||||
if blockHeader == nil {
|
||||
log.Error("[GetMasternodesByNumber] Unable to find block", "Num", blockNumber)
|
||||
return []common.Address{}
|
||||
}
|
||||
switch x.config.BlockConsensusVersion(big.NewInt(int64(blockNumber))) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
return x.EngineV2.GetMasternodes(chain, blockHeader)
|
||||
default: // Default "v1"
|
||||
return x.EngineV1.GetMasternodes(chain, blockHeader)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *XDPoS) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (int, int, int, bool, error) {
|
||||
switch x.config.BlockConsensusVersion(parent.Number) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
|
|
@ -302,30 +321,34 @@ func (x *XDPoS) RecoverValidator(header *types.Header) (common.Address, error) {
|
|||
}
|
||||
|
||||
// Get master nodes over extra data of previous checkpoint block.
|
||||
func (x *XDPoS) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address {
|
||||
switch x.config.BlockConsensusVersion(preCheckpointHeader.Number) {
|
||||
func (x *XDPoS) GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common.Address {
|
||||
switch x.config.BlockConsensusVersion(checkpointHeader.Number) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
return x.EngineV2.GetMasternodesFromEpochSwitchHeader(preCheckpointHeader)
|
||||
return x.EngineV2.GetMasternodesFromEpochSwitchHeader(checkpointHeader)
|
||||
default: // Default "v1"
|
||||
return x.EngineV1.GetMasternodesFromCheckpointHeader(preCheckpointHeader, n, e)
|
||||
return x.EngineV1.GetMasternodesFromCheckpointHeader(checkpointHeader)
|
||||
}
|
||||
}
|
||||
|
||||
// Check is epoch switch (checkpoint) block
|
||||
func (x *XDPoS) IsEpochSwitch(header *types.Header) bool {
|
||||
func (x *XDPoS) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
||||
switch x.config.BlockConsensusVersion(header.Number) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
b, _, err := x.EngineV2.IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("[IsEpochSwitch] Adaptor v2 IsEpochSwitch has error", "err", err)
|
||||
return false
|
||||
}
|
||||
return b
|
||||
return x.EngineV2.IsEpochSwitch(header)
|
||||
default: // Default "v1"
|
||||
return x.EngineV1.IsEpochSwitch(header)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *XDPoS) GetCurrentEpochSwitchBlock(chain consensus.ChainReader, blockNumber *big.Int) (uint64, uint64, error) {
|
||||
switch x.config.BlockConsensusVersion(blockNumber) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
return x.EngineV2.GetCurrentEpochSwitchBlock(chain, blockNumber)
|
||||
default: // Default "v1"
|
||||
return x.EngineV1.GetCurrentEpochSwitchBlock(blockNumber)
|
||||
}
|
||||
}
|
||||
|
||||
// Same DB across all consensus engines
|
||||
func (x *XDPoS) GetDb() ethdb.Database {
|
||||
return x.db
|
||||
|
|
|
|||
|
|
@ -53,6 +53,23 @@ type XDPoS_v1 struct {
|
|||
HookGetSignersFromContract func(blockHash common.Hash) ([]common.Address, error)
|
||||
}
|
||||
|
||||
/* V1 Block
|
||||
SignerFn is a signer callback function to request a hash to be signed by a
|
||||
backing account.
|
||||
type SignerFn func(accounts.Account, []byte) ([]byte, error)
|
||||
|
||||
sigHash returns the hash which is used as input for the delegated-proof-of-stake
|
||||
signing. It is the hash of the entire header apart from the 65 byte signature
|
||||
contained at the end of the extra data.
|
||||
|
||||
Note, the method requires the extra data to be at least 65 bytes, otherwise it
|
||||
panics. This is done to avoid accidentally using both forms (signature present
|
||||
or not), which could be abused to produce different hashes for the same header.
|
||||
*/
|
||||
func (x *XDPoS_v1) SigHash(header *types.Header) (hash common.Hash) {
|
||||
return sigHash(header)
|
||||
}
|
||||
|
||||
// New creates a XDPoS delegated-proof-of-stake consensus engine with the initial
|
||||
// signers set to the ones provided by the user.
|
||||
func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v1 {
|
||||
|
|
@ -81,7 +98,7 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v1 {
|
|||
// Author implements consensus.Engine, returning the Ethereum address recovered
|
||||
// from the signature in the header's extra-data section.
|
||||
func (x *XDPoS_v1) Author(header *types.Header) (common.Address, error) {
|
||||
return utils.Ecrecover(header, x.signatures)
|
||||
return ecrecover(header, x.signatures)
|
||||
}
|
||||
|
||||
// VerifyHeader checks whether a header conforms to the consensus rules.
|
||||
|
|
@ -296,7 +313,7 @@ func (x *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header
|
|||
return nil
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool {
|
||||
func (x *XDPoS_v1) IsAuthorisedAddress(chain consensus.ChainReader, header *types.Header, address common.Address) bool {
|
||||
snap, err := x.GetSnapshot(chain, header)
|
||||
if err != nil {
|
||||
log.Error("[IsAuthorisedAddress] Can't get snapshot with at ", "number", header.Number, "hash", header.Hash().Hex(), "err", err)
|
||||
|
|
@ -330,36 +347,37 @@ func (x *XDPoS_v1) StoreSnapshot(snap *SnapshotV1) error {
|
|||
return snap.store(x.db)
|
||||
}
|
||||
|
||||
func position(list []common.Address, x common.Address) int {
|
||||
for i, item := range list {
|
||||
if item == x {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address {
|
||||
n := header.Number.Uint64()
|
||||
e := x.config.Epoch
|
||||
switch {
|
||||
case n%e == 0:
|
||||
return x.GetMasternodesFromCheckpointHeader(header, n, e)
|
||||
return x.GetMasternodesFromCheckpointHeader(header)
|
||||
case n%e != 0:
|
||||
h := chain.GetHeaderByNumber(n - (n % e))
|
||||
return x.GetMasternodesFromCheckpointHeader(h, n, e)
|
||||
if h == nil {
|
||||
log.Warn("[GetMasternodes v1] epoch switch block header nil", "BlockNum", n)
|
||||
}
|
||||
return x.GetMasternodesFromCheckpointHeader(h)
|
||||
default:
|
||||
return []common.Address{}
|
||||
}
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) GetCurrentEpochSwitchBlock(blockNumber *big.Int) (uint64, uint64, error) {
|
||||
currentBlockNum := blockNumber.Uint64()
|
||||
currentCheckpointNumber := currentBlockNum - currentBlockNum%x.config.Epoch
|
||||
epochNumber := currentBlockNum / x.config.Epoch
|
||||
return currentCheckpointNumber, epochNumber, nil
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) GetPeriod() uint64 { return x.config.Period }
|
||||
|
||||
func whoIsCreator(snap *SnapshotV1, header *types.Header) (common.Address, error) {
|
||||
func (x *XDPoS_v1) whoIsCreator(snap *SnapshotV1, header *types.Header) (common.Address, error) {
|
||||
if header.Number.Uint64() == 0 {
|
||||
return common.Address{}, errors.New("Don't take block 0")
|
||||
}
|
||||
m, err := utils.Ecrecover(header, snap.sigcache)
|
||||
m, err := ecrecover(header, snap.sigcache)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
|
@ -390,13 +408,13 @@ func (x *XDPoS_v1) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
|||
// masternode[0] has chance to create block 1
|
||||
preIndex := -1
|
||||
if parent.Number.Uint64() != 0 {
|
||||
pre, err = whoIsCreator(snap, parent)
|
||||
pre, err = x.whoIsCreator(snap, parent)
|
||||
if err != nil {
|
||||
return 0, 0, 0, false, err
|
||||
}
|
||||
preIndex = position(masternodes, pre)
|
||||
preIndex = utils.Position(masternodes, pre)
|
||||
}
|
||||
curIndex := position(masternodes, signer)
|
||||
curIndex := utils.Position(masternodes, signer)
|
||||
if signer == x.signer {
|
||||
log.Debug("Masternodes cycle info", "number of masternodes", len(masternodes), "previous", pre, "position", preIndex, "current", signer, "position", curIndex)
|
||||
}
|
||||
|
|
@ -524,7 +542,7 @@ func (x *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header,
|
|||
}
|
||||
|
||||
// Resolve the authorization key and check against signers
|
||||
creator, err := utils.Ecrecover(header, x.signatures)
|
||||
creator, err := ecrecover(header, x.signatures)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -618,7 +636,7 @@ func (x *XDPoS_v1) GetValidator(creator common.Address, chain consensus.ChainRea
|
|||
return common.Address{}, fmt.Errorf("couldn't find checkpoint header")
|
||||
}
|
||||
}
|
||||
m, err := utils.GetM1M2FromCheckpointHeader(cpHeader, header, chain.Config())
|
||||
m, err := getM1M2FromCheckpointHeader(cpHeader, header, chain.Config())
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
|
@ -851,7 +869,7 @@ func (x *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-
|
|||
default:
|
||||
}
|
||||
// Sign all the things!
|
||||
sighash, err := signFn(accounts.Account{Address: signer}, utils.SigHash(header).Bytes())
|
||||
sighash, err := signFn(accounts.Account{Address: signer}, x.SigHash(header).Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -886,7 +904,7 @@ func (x *XDPoS_v1) calcDifficulty(chain consensus.ChainReader, parent *types.Hea
|
|||
}
|
||||
|
||||
func (x *XDPoS_v1) RecoverSigner(header *types.Header) (common.Address, error) {
|
||||
return utils.Ecrecover(header, x.signatures)
|
||||
return ecrecover(header, x.signatures)
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error) {
|
||||
|
|
@ -901,7 +919,7 @@ func (x *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error
|
|||
return common.Address{}, consensus.ErrFailValidatorSignature
|
||||
}
|
||||
// Recover the public key and the Ethereum address
|
||||
pubkey, err := crypto.Ecrecover(utils.SigHash(header).Bytes(), header.Validator)
|
||||
pubkey, err := crypto.Ecrecover(x.SigHash(header).Bytes(), header.Validator)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
|
@ -912,18 +930,13 @@ func (x *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error
|
|||
return signer, nil
|
||||
}
|
||||
|
||||
// Get master nodes over extra data of previous checkpoint block.
|
||||
func (x *XDPoS_v1) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address {
|
||||
if preCheckpointHeader == nil {
|
||||
log.Info("Previous checkpoint's header is empty", "block number", n, "epoch", e)
|
||||
// Get master nodes over extra data of checkpoint block.
|
||||
func (x *XDPoS_v1) GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common.Address {
|
||||
if checkpointHeader == nil {
|
||||
log.Warn("Checkpoint's header is empty", "Header", checkpointHeader)
|
||||
return []common.Address{}
|
||||
}
|
||||
masternodes := make([]common.Address, (len(preCheckpointHeader.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength)
|
||||
for i := 0; i < len(masternodes); i++ {
|
||||
copy(masternodes[i][:], preCheckpointHeader.Extra[utils.ExtraVanity+i*common.AddressLength:])
|
||||
}
|
||||
|
||||
return masternodes
|
||||
return decodeMasternodesFromHeaderExtra(checkpointHeader)
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) GetDb() ethdb.Database {
|
||||
|
|
@ -945,15 +958,6 @@ func removePenaltiesFromBlock(chain consensus.ChainReader, masternodes []common.
|
|||
return masternodes
|
||||
}
|
||||
|
||||
// Get masternodes address from checkpoint Header.
|
||||
func GetMasternodesFromCheckpointHeader(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
|
||||
}
|
||||
|
||||
func (x *XDPoS_v1) getSignersFromContract(chain consensus.ChainReader, checkpointHeader *types.Header) ([]common.Address, error) {
|
||||
startGapBlockHeader := checkpointHeader
|
||||
number := checkpointHeader.Number.Uint64()
|
||||
|
|
@ -990,6 +994,8 @@ func NewFaker(db ethdb.Database, config *params.XDPoSConfig) *XDPoS_v1 {
|
|||
}
|
||||
|
||||
// Epoch Switch is also known as checkpoint in v1
|
||||
func (x *XDPoS_v1) IsEpochSwitch(header *types.Header) bool {
|
||||
return (header.Number.Uint64() % x.config.Epoch) == 0
|
||||
func (x *XDPoS_v1) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
||||
epochNumber := header.Number.Uint64() / x.config.Epoch
|
||||
blockNumInEpoch := header.Number.Uint64() % x.config.Epoch
|
||||
return blockNumInEpoch == 0, epochNumber, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ func (s *SnapshotV1) apply(headers []*types.Header) (*SnapshotV1, error) {
|
|||
delete(snap.Recents, number-limit)
|
||||
}
|
||||
// Resolve the authorization key and check against signers
|
||||
signer, err := utils.Ecrecover(header, s.sigcache)
|
||||
signer, err := ecrecover(header, s.sigcache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
112
consensus/XDPoS/engines/engine_v1/utils.go
Normal file
112
consensus/XDPoS/engines/engine_v1/utils.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
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/sha3"
|
||||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
// 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 epoc.")
|
||||
}
|
||||
// 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.NewKeccak256()
|
||||
|
||||
err := rlp.Encode(hasher, []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)-65], // Yes, this will panic if extra is too short
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Fail to encode", err)
|
||||
}
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
// ecrecover extracts the Ethereum account address from a signed header.
|
||||
func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
|
||||
// If the signature's already cached, return that
|
||||
hash := header.Hash()
|
||||
if address, known := sigcache.Get(hash); known {
|
||||
return address.(common.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
|
||||
}
|
||||
49
consensus/XDPoS/engines/engine_v1/utils_test.go
Normal file
49
consensus/XDPoS/engines/engine_v1/utils_test.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package engine_v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
)
|
||||
|
||||
func TestGetM1M2FromCheckpointHeader(t *testing.T) {
|
||||
masternodes := []common.Address{
|
||||
common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
||||
common.StringToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
|
||||
common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc"),
|
||||
}
|
||||
validators := []int64{
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
}
|
||||
epoch := uint64(900)
|
||||
config := ¶ms.ChainConfig{
|
||||
XDPoS: ¶ms.XDPoSConfig{
|
||||
Epoch: uint64(epoch),
|
||||
},
|
||||
}
|
||||
testMoveM2 := []uint64{0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2}
|
||||
//try from block 3410001 to 3410018
|
||||
for i := uint64(3464001); i <= 3464018; i++ {
|
||||
currentNumber := int64(i)
|
||||
currentHeader := &types.Header{
|
||||
Number: big.NewInt(currentNumber),
|
||||
}
|
||||
m1m2, moveM2, err := getM1M2(masternodes, validators, currentHeader, config)
|
||||
if err != nil {
|
||||
t.Error("can't get m1m2", "err", err)
|
||||
}
|
||||
fmt.Printf("block: %v, moveM2: %v\n", currentHeader.Number.Int64(), moveM2)
|
||||
for _, k := range masternodes {
|
||||
fmt.Printf("m1: %v - m2: %v\n", k.Str(), m1m2[k].Str())
|
||||
}
|
||||
if moveM2 != testMoveM2[i-3464001] {
|
||||
t.Error("wrong moveM2", "currentNumber", currentNumber, "want", testMoveM2[i-3464001], "have", moveM2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,6 +98,23 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 {
|
|||
return engine
|
||||
}
|
||||
|
||||
/* V2 Block
|
||||
SignerFn is a signer callback function to request a hash to be signed by a
|
||||
backing account.
|
||||
type SignerFn func(accounts.Account, []byte) ([]byte, error)
|
||||
|
||||
sigHash returns the hash which is used as input for the delegated-proof-of-stake
|
||||
signing. It is the hash of the entire header apart from the 65 byte signature
|
||||
contained at the end of the extra data.
|
||||
|
||||
Note, the method requires the extra data to be at least 65 bytes, otherwise it
|
||||
panics. This is done to avoid accidentally using both forms (signature present
|
||||
or not), which could be abused to produce different hashes for the same header.
|
||||
*/
|
||||
func (x *XDPoS_v2) SignHash(header *types.Header) (hash common.Hash) {
|
||||
return sigHash(header)
|
||||
}
|
||||
|
||||
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
||||
// header for running the transactions on top.
|
||||
func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) error {
|
||||
|
|
@ -146,7 +163,12 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
|||
log.Debug("CalcDifficulty ", "number", header.Number, "difficulty", header.Difficulty)
|
||||
|
||||
// TODO: previous round should sit on previous Epoch and x.currentRound should >= Epoch number
|
||||
if number%x.config.Epoch == 0 {
|
||||
isEpochSwitchBlock, _, err := x.IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("[Prepare] Error while trying to determine if header is an epoch switch during Prepare", "header", header, "Error", err)
|
||||
return err
|
||||
}
|
||||
if isEpochSwitchBlock {
|
||||
snap, err := x.snapshot(chain, number-1, header.ParentHash, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -222,7 +244,7 @@ func (x *XDPoS_v2) Authorize(signer common.Address, signFn clique.SignerFn) {
|
|||
}
|
||||
|
||||
func (x *XDPoS_v2) Author(header *types.Header) (common.Address, error) {
|
||||
return utils.EcrecoverV2(header, x.signatures)
|
||||
return ecrecover(header, x.signatures)
|
||||
}
|
||||
|
||||
// Seal implements consensus.Engine, attempting to create a sealed block using
|
||||
|
|
@ -237,7 +259,11 @@ func (x *XDPoS_v2) Seal(chain consensus.ChainReader, block *types.Block, stop <-
|
|||
}
|
||||
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
|
||||
// checkpoint blocks have no tx
|
||||
if x.config.Period == 0 && len(block.Transactions()) == 0 && number%x.config.Epoch != 0 {
|
||||
isEpochSwitch, _, err := x.IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("[Seal] Error while checking whether header is a epoch switch during sealing", "Header", header)
|
||||
}
|
||||
if x.config.Period == 0 && len(block.Transactions()) == 0 && !isEpochSwitch {
|
||||
return nil, utils.ErrWaitTransactions
|
||||
}
|
||||
// Don't hold the signer fields for the entire sealing procedure
|
||||
|
|
@ -271,7 +297,7 @@ func (x *XDPoS_v2) Seal(chain consensus.ChainReader, block *types.Block, stop <-
|
|||
}
|
||||
|
||||
// Sign all the things!
|
||||
signature, err := signFn(accounts.Account{Address: signer}, utils.SigHashV2(header).Bytes())
|
||||
signature, err := signFn(accounts.Account{Address: signer}, sigHash(header).Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -327,7 +353,7 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
|||
return len(masternodes), preIndex, curIndex, false, nil
|
||||
}
|
||||
|
||||
func (x *XDPoS_v2) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool {
|
||||
func (x *XDPoS_v2) IsAuthorisedAddress(chain consensus.ChainReader, header *types.Header, address common.Address) bool {
|
||||
var extraField utils.ExtraFields_v2
|
||||
err := utils.DecodeBytesExtraFields(header.Extra, &extraField)
|
||||
if err != nil {
|
||||
|
|
@ -355,7 +381,7 @@ func whoIsCreator(snap *SnapshotV2, header *types.Header) (common.Address, error
|
|||
if header.Number.Uint64() == 0 {
|
||||
return common.Address{}, errors.New("Don't take block 0")
|
||||
}
|
||||
m, err := utils.EcrecoverV2(header, snap.sigcache)
|
||||
m, err := ecrecover(header, snap.sigcache)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
|
@ -1066,13 +1092,14 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
|||
parentRound := decodedExtraField.QuorumCert.ProposedBlockInfo.Round
|
||||
round := decodedExtraField.Round
|
||||
epochStart := round - round%utils.Round(x.config.Epoch)
|
||||
epochNum := x.config.XDPoSV2Block.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
|
||||
// if parent is last v1 block and this is first v2 block, this is treated as epoch switch
|
||||
if decodedExtraField.QuorumCert.ProposedBlockInfo.Number.Cmp(x.config.XDPoSV2Block) == 0 {
|
||||
log.Info("[IsEpochSwitch] true, parent equals XDPoSV2Block", "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
|
||||
return true, x.config.XDPoSV2Block.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch, nil
|
||||
return true, epochNum, nil
|
||||
}
|
||||
log.Info("[IsEpochSwitch]", "parent round", parentRound, "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
|
||||
return parentRound < epochStart, x.config.XDPoSV2Block.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch, nil
|
||||
return parentRound < epochStart, epochNum, nil
|
||||
}
|
||||
|
||||
// Given header and its hash, get epoch switch info from the epoch switch block of that epoch,
|
||||
|
|
@ -1133,3 +1160,16 @@ func (x *XDPoS_v2) GetMasternodes(chain consensus.ChainReader, header *types.Hea
|
|||
}
|
||||
return epochSwitchInfo.Masternodes
|
||||
}
|
||||
|
||||
func (x *XDPoS_v2) GetCurrentEpochSwitchBlock(chain consensus.ChainReader, blockNum *big.Int) (uint64, uint64, error) {
|
||||
header := chain.GetHeaderByNumber(blockNum.Uint64())
|
||||
epochSwitchInfo, err := x.getEpochSwitchInfo(chain, header, header.Hash())
|
||||
if err != nil {
|
||||
log.Error("[GetCurrentEpochSwitchBlock] Fail to get epoch switch info", "Num", header.Number, "Hash", header.Hash())
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
currentCheckpointNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64()
|
||||
epochNum := x.config.XDPoSV2Block.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
||||
return currentCheckpointNumber, epochNum, nil
|
||||
}
|
||||
|
|
|
|||
59
consensus/XDPoS/engines/engine_v2/utils.go
Normal file
59
consensus/XDPoS/engines/engine_v2/utils.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package engine_v2
|
||||
|
||||
import (
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
|
||||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
func sigHash(header *types.Header) (hash common.Hash) {
|
||||
hasher := sha3.NewKeccak256()
|
||||
|
||||
err := rlp.Encode(hasher, []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,
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
header.Validators,
|
||||
header.Penalties,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Fail to encode", err)
|
||||
}
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
|
||||
// If the signature's already cached, return that
|
||||
hash := header.Hash()
|
||||
if address, known := sigcache.Get(hash); known {
|
||||
return address.(common.Address), nil
|
||||
}
|
||||
|
||||
// Recover the public key and the Ethereum address
|
||||
pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), header.Validator)
|
||||
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
|
||||
}
|
||||
|
|
@ -2,20 +2,14 @@ package utils
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
|
||||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
func Position(list []common.Address, x common.Address) int {
|
||||
|
|
@ -55,51 +49,6 @@ func ExtractValidatorsFromBytes(byteValidators []byte) []int64 {
|
|||
return validators
|
||||
}
|
||||
|
||||
// Get masternodes address from checkpoint Header.
|
||||
func GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common.Address {
|
||||
masternodes := make([]common.Address, (len(checkpointHeader.Extra)-ExtraVanity-ExtraSeal)/common.AddressLength)
|
||||
for i := 0; i < len(masternodes); i++ {
|
||||
copy(masternodes[i][:], checkpointHeader.Extra[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 epoc.")
|
||||
}
|
||||
// Get signers from this block.
|
||||
masternodes := GetMasternodesFromCheckpointHeader(checkpointHeader)
|
||||
validators := 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
|
||||
}
|
||||
|
||||
// compare 2 signers lists
|
||||
// return true if they are same elements, otherwise return false
|
||||
func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool {
|
||||
|
|
@ -115,73 +64,6 @@ func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool {
|
|||
return reflect.DeepEqual(list1, list2)
|
||||
}
|
||||
|
||||
// SignerFn is a signer callback function to request a hash to be signed by a
|
||||
// backing account.
|
||||
//type SignerFn func(accounts.Account, []byte) ([]byte, error)
|
||||
|
||||
// sigHash returns the hash which is used as input for the delegated-proof-of-stake
|
||||
// signing. It is the hash of the entire header apart from the 65 byte signature
|
||||
// contained at the end of the extra data.
|
||||
//
|
||||
// Note, the method requires the extra data to be at least 65 bytes, otherwise it
|
||||
// panics. This is done to avoid accidentally using both forms (signature present
|
||||
// or not), which could be abused to produce different hashes for the same header.
|
||||
func SigHash(header *types.Header) (hash common.Hash) {
|
||||
hasher := sha3.NewKeccak256()
|
||||
|
||||
err := rlp.Encode(hasher, []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)-65], // Yes, this will panic if extra is too short
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Fail to encode", err)
|
||||
}
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
func SigHashV2(header *types.Header) (hash common.Hash) {
|
||||
hasher := sha3.NewKeccak256()
|
||||
|
||||
err := rlp.Encode(hasher, []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,
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
header.Validators,
|
||||
header.Penalties,
|
||||
})
|
||||
if err != nil {
|
||||
log.Debug("Fail to encode", err)
|
||||
}
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
// Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions)
|
||||
func DecodeBytesExtraFields(b []byte, val interface{}) error {
|
||||
if len(b) == 0 {
|
||||
|
|
@ -196,47 +78,3 @@ func DecodeBytesExtraFields(b []byte, val interface{}) error {
|
|||
return fmt.Errorf("consensus version %d is not defined", b[0])
|
||||
}
|
||||
}
|
||||
|
||||
// ecrecover extracts the Ethereum account address from a signed header.
|
||||
func Ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
|
||||
// If the signature's already cached, return that
|
||||
hash := header.Hash()
|
||||
if address, known := sigcache.Get(hash); known {
|
||||
return address.(common.Address), nil
|
||||
}
|
||||
// Retrieve the signature from the header extra-data
|
||||
if len(header.Extra) < ExtraSeal {
|
||||
return common.Address{}, ErrMissingSignature
|
||||
}
|
||||
signature := header.Extra[len(header.Extra)-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
|
||||
}
|
||||
|
||||
func EcrecoverV2(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
|
||||
// If the signature's already cached, return that
|
||||
hash := header.Hash()
|
||||
if address, known := sigcache.Get(hash); known {
|
||||
return address.(common.Address), nil
|
||||
}
|
||||
|
||||
// Recover the public key and the Ethereum address
|
||||
pubkey, err := crypto.Ecrecover(SigHashV2(header).Bytes(), header.Validator)
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +1,11 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
)
|
||||
|
||||
func TestGetM1M2FromCheckpointHeader(t *testing.T) {
|
||||
masternodes := []common.Address{
|
||||
common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
||||
common.StringToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
|
||||
common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc"),
|
||||
}
|
||||
validators := []int64{
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
}
|
||||
epoch := uint64(900)
|
||||
config := ¶ms.ChainConfig{
|
||||
XDPoS: ¶ms.XDPoSConfig{
|
||||
Epoch: uint64(epoch),
|
||||
},
|
||||
}
|
||||
testMoveM2 := []uint64{0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2}
|
||||
//try from block 3410001 to 3410018
|
||||
for i := uint64(3464001); i <= 3464018; i++ {
|
||||
currentNumber := int64(i)
|
||||
currentHeader := &types.Header{
|
||||
Number: big.NewInt(currentNumber),
|
||||
}
|
||||
m1m2, moveM2, err := GetM1M2(masternodes, validators, currentHeader, config)
|
||||
if err != nil {
|
||||
t.Error("can't get m1m2", "err", err)
|
||||
}
|
||||
fmt.Printf("block: %v, moveM2: %v\n", currentHeader.Number.Int64(), moveM2)
|
||||
for _, k := range masternodes {
|
||||
fmt.Printf("m1: %v - m2: %v\n", k.Str(), m1m2[k].Str())
|
||||
}
|
||||
if moveM2 != testMoveM2[i-3464001] {
|
||||
t.Error("wrong moveM2", "currentNumber", currentNumber, "want", testMoveM2[i-3464001], "have", moveM2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareSignersLists(t *testing.T) {
|
||||
list1 := []common.Address{
|
||||
common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
||||
|
|
@ -81,4 +39,4 @@ func TestCompareSignersLists(t *testing.T) {
|
|||
if CompareSignersLists([]common.Address{common.StringToAddress("aaaaaaaaaaaaaaaa")}, []common.Address{common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc")}) {
|
||||
t.Error("Failed with list has only one signer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) {
|
|||
ParentHash: currentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinBase),
|
||||
}
|
||||
err := generateSignature(backend, header)
|
||||
err := generateSignature(backend, adaptor, header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -66,11 +66,11 @@ func TestAdaptorGetMasternodesFromCheckpointHeader(t *testing.T) {
|
|||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
headerV1 := currentBlock.Header()
|
||||
headerV1.Extra = common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400")
|
||||
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1, 0, 0)
|
||||
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1)
|
||||
headerV2 := currentBlock.Header()
|
||||
headerV2.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(1))
|
||||
headerV2.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c")
|
||||
masternodesV2 := adaptor.GetMasternodesFromCheckpointHeader(headerV2, 0, 0)
|
||||
masternodesV2 := adaptor.GetMasternodesFromCheckpointHeader(headerV2)
|
||||
assert.True(t, reflect.DeepEqual(masternodesV1, masternodesV2), "GetMasternodesFromCheckpointHeader in adaptor for v1 v2 not equal", "v1", masternodesV1, "v2", masternodesV2)
|
||||
}
|
||||
func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||
|
|
@ -79,9 +79,15 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
header := currentBlock.Header()
|
||||
// v1
|
||||
header.Number.SetUint64(0)
|
||||
assert.True(t, adaptor.IsEpochSwitch(header), "header should be epoch switch", header)
|
||||
|
||||
isEpochSwitchBlock, epochNum, err := adaptor.IsEpochSwitch(header)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||
assert.Equal(t, uint64(0), epochNum)
|
||||
header.Number.SetUint64(1)
|
||||
assert.False(t, adaptor.IsEpochSwitch(header), "header should not be epoch switch", header)
|
||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||
// v2
|
||||
parentBlockInfo := &utils.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
|
|
@ -100,7 +106,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
header.Extra = extraBytes
|
||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(1))
|
||||
assert.True(t, adaptor.IsEpochSwitch(header), "header should be epoch switch", header)
|
||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||
parentBlockInfo = &utils.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
Round: utils.Round(1),
|
||||
|
|
@ -118,7 +126,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
header.Extra = extraBytes
|
||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(2))
|
||||
assert.False(t, adaptor.IsEpochSwitch(header), "header should not be epoch switch", header)
|
||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||
parentBlockInfo = &utils.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
Round: utils.Round(blockchain.Config().XDPoS.Epoch) - 1,
|
||||
|
|
@ -136,7 +146,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
header.Extra = extraBytes
|
||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(101))
|
||||
assert.True(t, adaptor.IsEpochSwitch(header), "header should be epoch switch", header)
|
||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||
parentBlockInfo = &utils.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
Round: utils.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
||||
|
|
@ -154,7 +166,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
header.Extra = extraBytes
|
||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(101))
|
||||
assert.False(t, adaptor.IsEpochSwitch(header), "header should not be epoch switch", header)
|
||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||
}
|
||||
|
||||
func TestAdaptorGetMasternodesV2(t *testing.T) {
|
||||
|
|
@ -173,6 +187,8 @@ func TestAdaptorGetMasternodesV2(t *testing.T) {
|
|||
}
|
||||
masternodes1 := adaptor.GetMasternodes(blockchain, currentBlock.Header())
|
||||
assert.Equal(t, 3, len(masternodes1))
|
||||
masternodes1ByNumber := adaptor.GetMasternodesByNumber(blockchain, currentBlock.NumberU64())
|
||||
assert.True(t, reflect.DeepEqual(masternodes1, masternodes1ByNumber), "at block number", blockNum)
|
||||
for blockNum = 12; blockNum < 15; blockNum++ {
|
||||
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn)
|
||||
currentBlock, err = insertBlock(blockchain, blockHeader)
|
||||
|
|
@ -181,5 +197,46 @@ func TestAdaptorGetMasternodesV2(t *testing.T) {
|
|||
}
|
||||
masternodes2 := adaptor.GetMasternodes(blockchain, currentBlock.Header())
|
||||
assert.True(t, reflect.DeepEqual(masternodes1, masternodes2), "at block number", blockNum)
|
||||
masternodes2ByNumber := adaptor.GetMasternodesByNumber(blockchain, currentBlock.NumberU64())
|
||||
assert.True(t, reflect.DeepEqual(masternodes2, masternodes2ByNumber), "at block number", blockNum)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrentEpochSwitchBlock(t *testing.T) {
|
||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 10, params.TestXDPoSMockChainConfigWithV2Engine, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
// V1
|
||||
currentCheckpointNumber, epochNum, err := adaptor.GetCurrentEpochSwitchBlock(blockchain, big.NewInt(9))
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, uint64(0), currentCheckpointNumber)
|
||||
assert.Equal(t, uint64(0), epochNum)
|
||||
|
||||
// V2
|
||||
blockNum := 11
|
||||
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||
blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn)
|
||||
// it contains 3 master nodes
|
||||
blockHeader.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c")
|
||||
// block 11 is the first v2 block, and is treated as epoch switch block
|
||||
currentBlock, err = insertBlock(blockchain, blockHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
currentCheckpointNumber, epochNum, err = adaptor.GetCurrentEpochSwitchBlock(blockchain, currentBlock.Number())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, uint64(11), currentCheckpointNumber)
|
||||
assert.Equal(t, uint64(0), epochNum)
|
||||
|
||||
for blockNum = 12; blockNum < 15; blockNum++ {
|
||||
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn)
|
||||
currentBlock, err = insertBlock(blockchain, blockHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
currentCheckpointNumber, epochNum, err := adaptor.GetCurrentEpochSwitchBlock(blockchain, currentBlock.Number())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, uint64(11), currentCheckpointNumber)
|
||||
assert.Equal(t, uint64(0), epochNum)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,10 +42,10 @@ func TestIsAuthorisedMNForConsensusV1(t *testing.T) {
|
|||
// Acc3 is the default account that is on the signerList
|
||||
|
||||
engine := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
isAuthorisedMN := engine.IsAuthorisedAddress(block449.Header(), blockchain, acc3Addr)
|
||||
isAuthorisedMN := engine.IsAuthorisedAddress(blockchain, block449.Header(), acc3Addr)
|
||||
assert.True(t, isAuthorisedMN)
|
||||
|
||||
isAuthorisedMN = engine.IsAuthorisedAddress(block449.Header(), blockchain, acc1Addr)
|
||||
isAuthorisedMN = engine.IsAuthorisedAddress(blockchain, block449.Header(), acc1Addr)
|
||||
assert.False(t, isAuthorisedMN)
|
||||
|
||||
// Now, let's mine another block to trigger the GAP block signerList update
|
||||
|
|
@ -62,9 +62,45 @@ func TestIsAuthorisedMNForConsensusV1(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
isAuthorisedMN = engine.IsAuthorisedAddress(block450.Header(), blockchain, acc3Addr)
|
||||
isAuthorisedMN = engine.IsAuthorisedAddress(blockchain, block450.Header(), acc3Addr)
|
||||
assert.False(t, isAuthorisedMN)
|
||||
|
||||
isAuthorisedMN = engine.IsAuthorisedAddress(block450.Header(), blockchain, acc1Addr)
|
||||
isAuthorisedMN = engine.IsAuthorisedAddress(blockchain, block450.Header(), acc1Addr)
|
||||
assert.True(t, isAuthorisedMN)
|
||||
}
|
||||
|
||||
func TestIsAuthorisedMNForConsensusV2(t *testing.T) {
|
||||
// we skip test for v1 since it's hard to make a real genesis block
|
||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 10, params.TestXDPoSMockChainConfigWithV2Engine, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
blockNum := 11
|
||||
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||
blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn)
|
||||
// it contains 3 master nodes
|
||||
// xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1
|
||||
// xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff
|
||||
// xdc065551F0dcAC6f00CAe11192D462db709bE3758c
|
||||
blockHeader.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c")
|
||||
// block 11 is the first v2 block, and is treated as epoch switch block
|
||||
currentBlock, err := insertBlock(blockchain, blockHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// the first block will start from 1
|
||||
isAuthorisedMN := adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff"))
|
||||
assert.True(t, isAuthorisedMN)
|
||||
// The third address hence not valid
|
||||
isAuthorisedMN = adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc065551F0dcAC6f00CAe11192D462db709bE3758c"))
|
||||
assert.False(t, isAuthorisedMN)
|
||||
|
||||
for blockNum = 12; blockNum < 16; blockNum++ {
|
||||
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn)
|
||||
currentBlock, err = insertBlock(blockchain, blockHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
isAuthorisedMN = adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc065551F0dcAC6f00CAe11192D462db709bE3758c"))
|
||||
assert.True(t, isAuthorisedMN)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,6 +262,10 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
checkpointChanMsg := <-core.CheckpointCh
|
||||
log.Info("[V1] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||
}()
|
||||
|
||||
return blockchain, backend, currentBlock, signer
|
||||
}
|
||||
|
|
@ -320,6 +324,10 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
checkpointChanMsg := <-core.CheckpointCh
|
||||
log.Info("[V2] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||
}()
|
||||
|
||||
return blockchain, backend, currentBlock, signer, signFn, currentForkBlock
|
||||
}
|
||||
|
|
@ -385,13 +393,13 @@ func createBlock(chainConfig *params.ChainConfig, startingBlock *types.Block, bl
|
|||
return header
|
||||
}
|
||||
|
||||
func generateSignature(backend *backends.SimulatedBackend, header *types.Header) error {
|
||||
func generateSignature(backend *backends.SimulatedBackend, adaptor *XDPoS.XDPoS, header *types.Header) error {
|
||||
signer, signFn, err := backends.SimulateWalletAddressAndSignFn()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Error while creating simulated wallet for generating singer address and signer fn: %v", err))
|
||||
}
|
||||
|
||||
signature, err := signFn(accounts.Account{Address: signer}, utils.SigHashV2(header).Bytes())
|
||||
signature, err := signFn(accounts.Account{Address: signer}, adaptor.SigHash(header).Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -488,7 +496,7 @@ func createXDPoSTestBlock(bc *BlockChain, customHeader *types.Header, txs []*typ
|
|||
Time: big.NewInt(customHeader.Number.Int64() * 10),
|
||||
Extra: customHeader.Extra,
|
||||
Validator: customHeader.Validator,
|
||||
Validators: customHeader.Validators,
|
||||
Validators: customHeader.Validators,
|
||||
}
|
||||
var block *types.Block
|
||||
if len(txs) == 0 {
|
||||
|
|
|
|||
|
|
@ -352,8 +352,7 @@ func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header
|
|||
}
|
||||
}
|
||||
header = chain.GetHeader(header.ParentHash, prevCheckpoint)
|
||||
//TODO: i think this should be c.GetMasternodesFrom...
|
||||
masternodes := utils.GetMasternodesFromCheckpointHeader(header)
|
||||
masternodes := c.GetMasternodesFromCheckpointHeader(header)
|
||||
|
||||
for i := startBlockNumber; i <= endBlockNumber; i++ {
|
||||
if i%common.MergeSignRange == 0 || !chain.Config().IsTIP2019(big.NewInt(int64(i))) {
|
||||
|
|
|
|||
|
|
@ -17,11 +17,12 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||
|
|
|
|||
|
|
@ -1590,8 +1590,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
|
|||
bc.reportBlock(block, nil, err)
|
||||
return i, events, coalescedLogs, err
|
||||
}
|
||||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
||||
if err := tradingService.UpdateMediumPriceBeforeEpoch(block.NumberU64()/bc.chainConfig.XDPoS.Epoch, tradingState, statedb); err != nil {
|
||||
isEpochSwithBlock, epochNumber, err := engine.IsEpochSwitch(block.Header())
|
||||
if err != nil {
|
||||
log.Error("[insertChain] Error while checking if the incoming block is epoch switch block", "Hash", block.Hash(), "Number", block.Number())
|
||||
bc.reportBlock(block, nil, err)
|
||||
}
|
||||
if isEpochSwithBlock {
|
||||
if err := tradingService.UpdateMediumPriceBeforeEpoch(epochNumber, tradingState, statedb); err != nil {
|
||||
return i, events, coalescedLogs, err
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1708,9 +1713,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
|
|||
stats.report(chain, i, dirty)
|
||||
if bc.chainConfig.XDPoS != nil {
|
||||
// epoch block
|
||||
if (chain[i].NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
||||
isEpochSwithBlock, _, err := engine.IsEpochSwitch(chain[i].Header())
|
||||
if err != nil {
|
||||
log.Error("[insertChain] Error while checking and notifying channel CheckpointCh if the incoming block is epoch switch block", "Hash", block.Hash(), "Number", block.Number())
|
||||
bc.reportBlock(block, nil, err)
|
||||
}
|
||||
if isEpochSwithBlock {
|
||||
CheckpointCh <- 1
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1855,8 +1864,15 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu
|
|||
bc.reportBlock(block, nil, err)
|
||||
return nil, err
|
||||
}
|
||||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
||||
if err := tradingService.UpdateMediumPriceBeforeEpoch(block.NumberU64()/bc.chainConfig.XDPoS.Epoch, tradingState, statedb); err != nil {
|
||||
|
||||
isEpochSwithBlock, epochNumber, err := engine.IsEpochSwitch(block.Header())
|
||||
if err != nil {
|
||||
log.Error("[getResultBlock] Error while checking block is epoch switch block", "Hash", block.Hash(), "Number", block.Number())
|
||||
bc.reportBlock(block, nil, err)
|
||||
}
|
||||
|
||||
if isEpochSwithBlock {
|
||||
if err := tradingService.UpdateMediumPriceBeforeEpoch(epochNumber, tradingState, statedb); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2029,7 +2045,12 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L
|
|||
stats.report(types.Blocks{block}, 0, dirty)
|
||||
if bc.chainConfig.XDPoS != nil {
|
||||
// epoch block
|
||||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
||||
isEpochSwithBlock, _, err := bc.Engine().(*XDPoS.XDPoS).IsEpochSwitch(block.Header())
|
||||
if err != nil {
|
||||
log.Error("[insertBlock] Error while checking if the incoming block is epoch switch block", "Hash", block.Hash(), "Number", block.Number())
|
||||
bc.reportBlock(block, nil, err)
|
||||
}
|
||||
if isEpochSwithBlock {
|
||||
CheckpointCh <- 1
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,17 @@ func (b *EthApiBackend) GetVotersRewards(masternodeAddr common.Address) map[comm
|
|||
number := block.Number().Uint64()
|
||||
engine := b.GetEngine().(*XDPoS.XDPoS)
|
||||
foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr
|
||||
lastCheckpointNumber := number - (number % b.ChainConfig().XDPoS.Epoch) - b.ChainConfig().XDPoS.Epoch // calculate for 2 epochs ago
|
||||
|
||||
// calculate for 2 epochs ago
|
||||
currentCheckpointNumber, _, err := engine.GetCurrentEpochSwitchBlock(chain, block.Number())
|
||||
if err != nil {
|
||||
log.Error("[GetVotersRewards] Fail to get GetCurrentEpochSwitchBlock for current checkpoint block", "block", block)
|
||||
}
|
||||
lastCheckpointNumber, _, err := engine.GetCurrentEpochSwitchBlock(chain, big.NewInt(int64(currentCheckpointNumber-1)))
|
||||
if err != nil {
|
||||
log.Error("[GetVotersRewards] Fail to get GetCurrentEpochSwitchBlock for last checkpoint block", "block", block)
|
||||
}
|
||||
|
||||
lastCheckpointBlock := chain.GetBlockByNumber(lastCheckpointNumber)
|
||||
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
|
||||
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ func New(ctx *node.ServiceContext, config *Config, XDCXServ *XDCx.XDCX, lendingS
|
|||
return block, false, err
|
||||
}
|
||||
header := block.Header()
|
||||
sighash, err := wallet.SignHash(accounts.Account{Address: eb}, XDPoS.SigHash(header).Bytes())
|
||||
sighash, err := wallet.SignHash(accounts.Account{Address: eb}, c.SigHash(header).Bytes())
|
||||
if err != nil || sighash == nil {
|
||||
log.Error("Can't get signature hash of m2", "sighash", sighash, "err", err)
|
||||
return block, false, err
|
||||
|
|
@ -296,7 +296,7 @@ func New(ctx *node.ServiceContext, config *Config, XDCXServ *XDCx.XDCX, lendingS
|
|||
// not genesis block
|
||||
header = parentHeader
|
||||
}
|
||||
return c.IsAuthorisedAddress(header, eth.blockchain, address)
|
||||
return c.IsAuthorisedAddress(eth.blockchain, header, address)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -364,7 +364,7 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chai
|
|||
// APIs returns the collection of RPC services the ethereum package offers.
|
||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||
func (s *Ethereum) APIs() []rpc.API {
|
||||
apis := ethapi.GetAPIs(s.ApiBackend)
|
||||
apis := ethapi.GetAPIs(s.ApiBackend, s.BlockChain())
|
||||
|
||||
// Append any APIs exposed explicitly by the consensus engine
|
||||
apis = append(apis, s.engine.APIs(s.BlockChain())...)
|
||||
|
|
@ -464,7 +464,7 @@ func (s *Ethereum) ValidateMasternode() (bool, error) {
|
|||
//check if miner's wallet is in set of validators
|
||||
c := s.engine.(*XDPoS.XDPoS)
|
||||
|
||||
authorized := c.IsAuthorisedAddress(s.blockchain.CurrentHeader(), s.blockchain, eb)
|
||||
authorized := c.IsAuthorisedAddress(s.blockchain, s.blockchain.CurrentHeader(), eb)
|
||||
if !authorized {
|
||||
//This miner doesn't belong to set of validators
|
||||
return false, nil
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
|
||||
|
||||
|
|
@ -497,12 +498,16 @@ func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args Sen
|
|||
// PublicBlockChainAPI provides an API to access the Ethereum blockchain.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicBlockChainAPI struct {
|
||||
b Backend
|
||||
b Backend
|
||||
chainReader consensus.ChainReader
|
||||
}
|
||||
|
||||
// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
|
||||
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
|
||||
return &PublicBlockChainAPI{b}
|
||||
func NewPublicBlockChainAPI(b Backend, chainReader consensus.ChainReader) *PublicBlockChainAPI {
|
||||
return &PublicBlockChainAPI{
|
||||
b,
|
||||
chainReader,
|
||||
}
|
||||
}
|
||||
|
||||
// BlockNumber returns the block number of the chain head.
|
||||
|
|
@ -694,11 +699,7 @@ func (s *PublicBlockChainAPI) GetMasternodes(ctx context.Context, b *types.Block
|
|||
}
|
||||
if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok {
|
||||
// Get block epoc latest.
|
||||
lastCheckpointNumber := prevBlockNumber - (prevBlockNumber % s.b.ChainConfig().XDPoS.Epoch)
|
||||
prevCheckpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(lastCheckpointNumber))
|
||||
if prevCheckpointBlock != nil {
|
||||
masternodes = engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), curBlockNumber, s.b.ChainConfig().XDPoS.Epoch)
|
||||
}
|
||||
return engine.GetMasternodesByNumber(s.chainReader, prevBlockNumber), nil
|
||||
} else {
|
||||
log.Error("Undefined XDPoS consensus engine")
|
||||
}
|
||||
|
|
@ -791,7 +792,7 @@ func (s *PublicBlockChainAPI) GetCandidateStatus(ctx context.Context, coinbaseAd
|
|||
|
||||
// Second, Find candidates that have masternode status
|
||||
if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok {
|
||||
masternodes = engine.GetMasternodesFromCheckpointHeader(header, block.Number().Uint64(), s.b.ChainConfig().XDPoS.Epoch)
|
||||
masternodes = engine.GetMasternodesFromCheckpointHeader(header)
|
||||
if len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
||||
result[fieldSuccess] = false
|
||||
|
|
@ -902,7 +903,7 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch
|
|||
|
||||
// Second, Find candidates that have masternode status
|
||||
if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok {
|
||||
masternodes = engine.GetMasternodesFromCheckpointHeader(header, block.Number().Uint64(), s.b.ChainConfig().XDPoS.Epoch)
|
||||
masternodes = engine.GetMasternodesFromCheckpointHeader(header)
|
||||
if len(masternodes) == 0 {
|
||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
||||
result[fieldSuccess] = false
|
||||
|
|
@ -965,21 +966,22 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch
|
|||
// GetPreviousCheckpointFromEpoch returns header of the previous checkpoint
|
||||
func (s *PublicBlockChainAPI) GetPreviousCheckpointFromEpoch(ctx context.Context, epochNum rpc.EpochNumber) (rpc.BlockNumber, rpc.EpochNumber) {
|
||||
var checkpointNumber uint64
|
||||
epoch := s.b.ChainConfig().XDPoS.Epoch
|
||||
|
||||
currentCheckpointNumber, epochNumber, err := s.b.GetEngine().(*XDPoS.XDPoS).GetCurrentEpochSwitchBlock(s.chainReader, s.b.CurrentBlock().Number())
|
||||
if err != nil {
|
||||
log.Error("[GetPreviousCheckpointFromEpoch] Error while trying to get current epoch switch block information", "Block", s.b.CurrentBlock(), "Error", err)
|
||||
}
|
||||
if epochNum == rpc.LatestEpochNumber {
|
||||
blockNumer := s.b.CurrentBlock().Number().Uint64()
|
||||
diff := blockNumer % epoch
|
||||
// checkpoint number
|
||||
checkpointNumber = blockNumer - diff
|
||||
epochNum = rpc.EpochNumber(checkpointNumber / epoch)
|
||||
if diff > 0 {
|
||||
epochNum += 1
|
||||
}
|
||||
checkpointNumber = currentCheckpointNumber
|
||||
epochNum = rpc.EpochNumber(epochNumber)
|
||||
} else if epochNum < 2 {
|
||||
checkpointNumber = 0
|
||||
} else {
|
||||
checkpointNumber = epoch * (uint64(epochNum) - 1)
|
||||
blockNumberBeforeCurrentEpochSwitch := currentCheckpointNumber - 1
|
||||
checkpointNumber, _, err = s.b.GetEngine().(*XDPoS.XDPoS).GetCurrentEpochSwitchBlock(s.chainReader, big.NewInt(int64(blockNumberBeforeCurrentEpochSwitch)))
|
||||
if err != nil {
|
||||
log.Error("[GetPreviousCheckpointFromEpoch] Error while trying to get last epoch switch block information", "Number", blockNumberBeforeCurrentEpochSwitch, "Error", err)
|
||||
}
|
||||
}
|
||||
return rpc.BlockNumber(checkpointNumber), epochNum
|
||||
}
|
||||
|
|
@ -1301,7 +1303,11 @@ func (s *PublicBlockChainAPI) findNearestSignedBlock(ctx context.Context, b *typ
|
|||
}
|
||||
|
||||
// Get block epoc latest
|
||||
checkpointNumber := signedBlockNumber - (signedBlockNumber % s.b.ChainConfig().XDPoS.Epoch)
|
||||
checkpointNumber, _, err := s.b.GetEngine().(*XDPoS.XDPoS).GetCurrentEpochSwitchBlock(s.chainReader, big.NewInt(int64(signedBlockNumber)))
|
||||
if err != nil {
|
||||
log.Error("[findNearestSignedBlock] Error while trying to get current Epoch switch block", "Number", signedBlockNumber)
|
||||
}
|
||||
|
||||
checkpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
||||
|
||||
if checkpointBlock != nil {
|
||||
|
|
@ -1385,13 +1391,9 @@ func (s *PublicBlockChainAPI) getSigners(ctx context.Context, block *types.Block
|
|||
var err error
|
||||
var filterSigners []common.Address
|
||||
var signers []common.Address
|
||||
blockNumber := block.Number().Uint64()
|
||||
|
||||
// Get block epoc latest.
|
||||
checkpointNumber := blockNumber - (blockNumber % s.b.ChainConfig().XDPoS.Epoch)
|
||||
checkpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
||||
masternodes := engine.GetMasternodes(s.chainReader, block.Header())
|
||||
|
||||
masternodes := engine.GetMasternodesFromCheckpointHeader(checkpointBlock.Header(), blockNumber, s.b.ChainConfig().XDPoS.Epoch)
|
||||
signers, err = GetSignersFromBlocks(s.b, block.NumberU64(), block.Hash(), masternodes)
|
||||
if err != nil {
|
||||
log.Error("Fail to get signers from block signer SC.", "error", err)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ type Backend interface {
|
|||
GetOrderNonce(address common.Hash) (uint64, error)
|
||||
}
|
||||
|
||||
func GetAPIs(apiBackend Backend) []rpc.API {
|
||||
func GetAPIs(apiBackend Backend, chainReader consensus.ChainReader) []rpc.API {
|
||||
nonceLock := new(AddrLocker)
|
||||
return []rpc.API{
|
||||
{
|
||||
|
|
@ -108,7 +108,7 @@ func GetAPIs(apiBackend Backend) []rpc.API {
|
|||
}, {
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
Service: NewPublicBlockChainAPI(apiBackend),
|
||||
Service: NewPublicBlockChainAPI(apiBackend, chainReader),
|
||||
Public: true,
|
||||
}, {
|
||||
Namespace: "eth",
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ func (s *LightDummyAPI) Mining() bool {
|
|||
// APIs returns the collection of RPC services the ethereum package offers.
|
||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||
func (s *LightEthereum) APIs() []rpc.API {
|
||||
return append(ethapi.GetAPIs(s.ApiBackend), []rpc.API{
|
||||
return append(ethapi.GetAPIs(s.ApiBackend, nil), []rpc.API{
|
||||
{
|
||||
Namespace: "eth",
|
||||
Version: "1.0",
|
||||
|
|
|
|||
|
|
@ -381,7 +381,11 @@ func (self *worker) wait() {
|
|||
}
|
||||
if work.config.XDPoS != nil {
|
||||
// epoch block
|
||||
if (block.NumberU64() % work.config.XDPoS.Epoch) == 0 {
|
||||
isEpochSwitchBlock, _, err := self.engine.(*XDPoS.XDPoS).IsEpochSwitch(block.Header())
|
||||
if err != nil {
|
||||
log.Error("[wait] fail to check if block is epoch switch block when worker waiting", "BlockNum", block.Number(), "Hash", block.Hash())
|
||||
}
|
||||
if isEpochSwitchBlock {
|
||||
core.CheckpointCh <- 1
|
||||
}
|
||||
}
|
||||
|
|
@ -402,7 +406,7 @@ func (self *worker) wait() {
|
|||
log.Error("[wait] Unable to handle new proposed block", "err", err, "number", block.Number(), "hash", block.Hash())
|
||||
}
|
||||
|
||||
authorized := c.IsAuthorisedAddress(block.Header(), self.chain, self.coinbase)
|
||||
authorized := c.IsAuthorisedAddress(self.chain, block.Header(), self.coinbase)
|
||||
if !authorized {
|
||||
valid := false
|
||||
masternodes := c.GetMasternodes(self.chain, block.Header())
|
||||
|
|
@ -635,13 +639,19 @@ func (self *worker) commitNewWork() {
|
|||
lendingFinalizedTradeTransaction *types.Transaction
|
||||
)
|
||||
feeCapacity := state.GetTRC21FeeCapacityFromStateWithCache(parent.Root(), work.state)
|
||||
if self.config.XDPoS != nil && header.Number.Uint64()%self.config.XDPoS.Epoch != 0 {
|
||||
pending, err := self.eth.TxPool().Pending()
|
||||
if self.config.XDPoS != nil {
|
||||
isEpochSwitchBlock, _, err := self.engine.(*XDPoS.XDPoS).IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch pending transactions", "err", err)
|
||||
return
|
||||
log.Error("[commitNewWork] fail to check if block is epoch switch block when fetching pending transactions", "BlockNum", header.Number, "Hash", header.Hash())
|
||||
}
|
||||
if !isEpochSwitchBlock {
|
||||
pending, err := self.eth.TxPool().Pending()
|
||||
if err != nil {
|
||||
log.Error("Failed to fetch pending transactions", "err", err)
|
||||
return
|
||||
}
|
||||
txs, specialTxs = types.NewTransactionsByPriceAndNonce(self.current.signer, pending, signers, feeCapacity)
|
||||
}
|
||||
txs, specialTxs = types.NewTransactionsByPriceAndNonce(self.current.signer, pending, signers, feeCapacity)
|
||||
}
|
||||
if atomic.LoadInt32(&self.mining) == 1 {
|
||||
wallet, err := self.eth.AccountManager().Find(accounts.Account{Address: self.coinbase})
|
||||
|
|
@ -653,16 +663,20 @@ func (self *worker) commitNewWork() {
|
|||
XDCX := self.eth.GetXDCX()
|
||||
XDCXLending := self.eth.GetXDCXLending()
|
||||
if XDCX != nil && header.Number.Uint64() > self.config.XDPoS.Epoch {
|
||||
if header.Number.Uint64()%self.config.XDPoS.Epoch == 0 {
|
||||
err := XDCX.UpdateMediumPriceBeforeEpoch(header.Number.Uint64()/self.config.XDPoS.Epoch, work.tradingState, work.state)
|
||||
isEpochSwitchBlock, epochNumber, err := self.engine.(*XDPoS.XDPoS).IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("[commitNewWork] fail to check if block is epoch switch block when performing XDCX and XDCXLending operations", "BlockNum", header.Number, "Hash", header.Hash())
|
||||
}
|
||||
|
||||
if isEpochSwitchBlock {
|
||||
err := XDCX.UpdateMediumPriceBeforeEpoch(epochNumber, work.tradingState, work.state)
|
||||
if err != nil {
|
||||
log.Error("Fail when update medium price last epoch", "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
// won't grasp tx at checkpoint
|
||||
//https://github.com/XinFinOrg/XDPoSChain-v1/pull/416
|
||||
if header.Number.Uint64()%self.config.XDPoS.Epoch != 0 {
|
||||
} else {
|
||||
// won't grasp tx at checkpoint
|
||||
//https://github.com/XinFinOrg/XDPoSChain-v1/pull/416
|
||||
log.Debug("Start processing order pending")
|
||||
tradingOrderPending, _ := self.eth.OrderPool().Pending()
|
||||
log.Debug("Start processing order pending", "len", len(tradingOrderPending))
|
||||
|
|
@ -680,6 +694,7 @@ func (self *worker) commitNewWork() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(tradingTxMatches) > 0 {
|
||||
txMatchBatch := &tradingstate.TxMatchBatch{
|
||||
Data: tradingTxMatches,
|
||||
|
|
@ -1062,10 +1077,16 @@ func (env *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Ad
|
|||
}
|
||||
go func(logs []*types.Log, tcount int) {
|
||||
if len(logs) > 0 {
|
||||
mux.Post(core.PendingLogsEvent{Logs: logs})
|
||||
err := mux.Post(core.PendingLogsEvent{Logs: logs})
|
||||
if err != nil {
|
||||
log.Warn("[commitTransactions] Error when sending PendingLogsEvent", "LogLength", len(logs))
|
||||
}
|
||||
}
|
||||
if tcount > 0 {
|
||||
mux.Post(core.PendingStateEvent{})
|
||||
err := mux.Post(core.PendingStateEvent{})
|
||||
if err != nil {
|
||||
log.Warn("[commitTransactions] Error when sending PendingStateEvent", "tcount", tcount)
|
||||
}
|
||||
}
|
||||
}(cpy, env.tcount)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue