mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +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"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SigHash(header *types.Header) (hash common.Hash) {
|
func (x *XDPoS) SigHash(header *types.Header) (hash common.Hash) {
|
||||||
return utils.SigHash(header)
|
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
|
// 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
|
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) {
|
switch x.config.BlockConsensusVersion(header.Number) {
|
||||||
case params.ConsensusEngineVersion2:
|
case params.ConsensusEngineVersion2:
|
||||||
return x.EngineV2.IsAuthorisedAddress(header, chain, address)
|
return x.EngineV2.IsAuthorisedAddress(chain, header, address)
|
||||||
default: // Default "v1"
|
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) {
|
func (x *XDPoS) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (int, int, int, bool, error) {
|
||||||
switch x.config.BlockConsensusVersion(parent.Number) {
|
switch x.config.BlockConsensusVersion(parent.Number) {
|
||||||
case params.ConsensusEngineVersion2:
|
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.
|
// Get master nodes over extra data of previous checkpoint block.
|
||||||
func (x *XDPoS) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address {
|
func (x *XDPoS) GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common.Address {
|
||||||
switch x.config.BlockConsensusVersion(preCheckpointHeader.Number) {
|
switch x.config.BlockConsensusVersion(checkpointHeader.Number) {
|
||||||
case params.ConsensusEngineVersion2:
|
case params.ConsensusEngineVersion2:
|
||||||
return x.EngineV2.GetMasternodesFromEpochSwitchHeader(preCheckpointHeader)
|
return x.EngineV2.GetMasternodesFromEpochSwitchHeader(checkpointHeader)
|
||||||
default: // Default "v1"
|
default: // Default "v1"
|
||||||
return x.EngineV1.GetMasternodesFromCheckpointHeader(preCheckpointHeader, n, e)
|
return x.EngineV1.GetMasternodesFromCheckpointHeader(checkpointHeader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check is epoch switch (checkpoint) block
|
// 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) {
|
switch x.config.BlockConsensusVersion(header.Number) {
|
||||||
case params.ConsensusEngineVersion2:
|
case params.ConsensusEngineVersion2:
|
||||||
b, _, err := x.EngineV2.IsEpochSwitch(header)
|
return x.EngineV2.IsEpochSwitch(header)
|
||||||
if err != nil {
|
|
||||||
log.Error("[IsEpochSwitch] Adaptor v2 IsEpochSwitch has error", "err", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
default: // Default "v1"
|
default: // Default "v1"
|
||||||
return x.EngineV1.IsEpochSwitch(header)
|
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
|
// Same DB across all consensus engines
|
||||||
func (x *XDPoS) GetDb() ethdb.Database {
|
func (x *XDPoS) GetDb() ethdb.Database {
|
||||||
return x.db
|
return x.db
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,23 @@ type XDPoS_v1 struct {
|
||||||
HookGetSignersFromContract func(blockHash common.Hash) ([]common.Address, error)
|
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
|
// New creates a XDPoS delegated-proof-of-stake consensus engine with the initial
|
||||||
// signers set to the ones provided by the user.
|
// signers set to the ones provided by the user.
|
||||||
func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v1 {
|
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
|
// Author implements consensus.Engine, returning the Ethereum address recovered
|
||||||
// from the signature in the header's extra-data section.
|
// from the signature in the header's extra-data section.
|
||||||
func (x *XDPoS_v1) Author(header *types.Header) (common.Address, error) {
|
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.
|
// 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
|
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)
|
snap, err := x.GetSnapshot(chain, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[IsAuthorisedAddress] Can't get snapshot with at ", "number", header.Number, "hash", header.Hash().Hex(), "err", err)
|
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)
|
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 {
|
func (x *XDPoS_v1) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address {
|
||||||
n := header.Number.Uint64()
|
n := header.Number.Uint64()
|
||||||
e := x.config.Epoch
|
e := x.config.Epoch
|
||||||
switch {
|
switch {
|
||||||
case n%e == 0:
|
case n%e == 0:
|
||||||
return x.GetMasternodesFromCheckpointHeader(header, n, e)
|
return x.GetMasternodesFromCheckpointHeader(header)
|
||||||
case n%e != 0:
|
case n%e != 0:
|
||||||
h := chain.GetHeaderByNumber(n - (n % e))
|
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:
|
default:
|
||||||
return []common.Address{}
|
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 (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 {
|
if header.Number.Uint64() == 0 {
|
||||||
return common.Address{}, errors.New("Don't take block 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 {
|
if err != nil {
|
||||||
return common.Address{}, err
|
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
|
// masternode[0] has chance to create block 1
|
||||||
preIndex := -1
|
preIndex := -1
|
||||||
if parent.Number.Uint64() != 0 {
|
if parent.Number.Uint64() != 0 {
|
||||||
pre, err = whoIsCreator(snap, parent)
|
pre, err = x.whoIsCreator(snap, parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, 0, false, err
|
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 {
|
if signer == x.signer {
|
||||||
log.Debug("Masternodes cycle info", "number of masternodes", len(masternodes), "previous", pre, "position", preIndex, "current", signer, "position", curIndex)
|
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
|
// Resolve the authorization key and check against signers
|
||||||
creator, err := utils.Ecrecover(header, x.signatures)
|
creator, err := ecrecover(header, x.signatures)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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")
|
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 {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -851,7 +869,7 @@ func (x *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
// Sign all the things!
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
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) {
|
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) {
|
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
|
return common.Address{}, consensus.ErrFailValidatorSignature
|
||||||
}
|
}
|
||||||
// Recover the public key and the Ethereum address
|
// 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 {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -912,18 +930,13 @@ func (x *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error
|
||||||
return signer, nil
|
return signer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get master nodes over extra data of previous checkpoint block.
|
// Get master nodes over extra data of checkpoint block.
|
||||||
func (x *XDPoS_v1) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address {
|
func (x *XDPoS_v1) GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common.Address {
|
||||||
if preCheckpointHeader == nil {
|
if checkpointHeader == nil {
|
||||||
log.Info("Previous checkpoint's header is empty", "block number", n, "epoch", e)
|
log.Warn("Checkpoint's header is empty", "Header", checkpointHeader)
|
||||||
return []common.Address{}
|
return []common.Address{}
|
||||||
}
|
}
|
||||||
masternodes := make([]common.Address, (len(preCheckpointHeader.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength)
|
return decodeMasternodesFromHeaderExtra(checkpointHeader)
|
||||||
for i := 0; i < len(masternodes); i++ {
|
|
||||||
copy(masternodes[i][:], preCheckpointHeader.Extra[utils.ExtraVanity+i*common.AddressLength:])
|
|
||||||
}
|
|
||||||
|
|
||||||
return masternodes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v1) GetDb() ethdb.Database {
|
func (x *XDPoS_v1) GetDb() ethdb.Database {
|
||||||
|
|
@ -945,15 +958,6 @@ func removePenaltiesFromBlock(chain consensus.ChainReader, masternodes []common.
|
||||||
return masternodes
|
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) {
|
func (x *XDPoS_v1) getSignersFromContract(chain consensus.ChainReader, checkpointHeader *types.Header) ([]common.Address, error) {
|
||||||
startGapBlockHeader := checkpointHeader
|
startGapBlockHeader := checkpointHeader
|
||||||
number := checkpointHeader.Number.Uint64()
|
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
|
// Epoch Switch is also known as checkpoint in v1
|
||||||
func (x *XDPoS_v1) IsEpochSwitch(header *types.Header) bool {
|
func (x *XDPoS_v1) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
||||||
return (header.Number.Uint64() % x.config.Epoch) == 0
|
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)
|
delete(snap.Recents, number-limit)
|
||||||
}
|
}
|
||||||
// Resolve the authorization key and check against signers
|
// Resolve the authorization key and check against signers
|
||||||
signer, err := utils.Ecrecover(header, s.sigcache)
|
signer, err := ecrecover(header, s.sigcache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
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
|
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
||||||
// header for running the transactions on top.
|
// header for running the transactions on top.
|
||||||
func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) error {
|
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)
|
log.Debug("CalcDifficulty ", "number", header.Number, "difficulty", header.Difficulty)
|
||||||
|
|
||||||
// TODO: previous round should sit on previous Epoch and x.currentRound should >= Epoch number
|
// 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)
|
snap, err := x.snapshot(chain, number-1, header.ParentHash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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) {
|
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
|
// 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)
|
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
|
||||||
// checkpoint blocks have no tx
|
// 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
|
return nil, utils.ErrWaitTransactions
|
||||||
}
|
}
|
||||||
// Don't hold the signer fields for the entire sealing procedure
|
// 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!
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
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
|
var extraField utils.ExtraFields_v2
|
||||||
err := utils.DecodeBytesExtraFields(header.Extra, &extraField)
|
err := utils.DecodeBytesExtraFields(header.Extra, &extraField)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -355,7 +381,7 @@ func whoIsCreator(snap *SnapshotV2, header *types.Header) (common.Address, error
|
||||||
if header.Number.Uint64() == 0 {
|
if header.Number.Uint64() == 0 {
|
||||||
return common.Address{}, errors.New("Don't take block 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 {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1066,13 +1092,14 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
||||||
parentRound := decodedExtraField.QuorumCert.ProposedBlockInfo.Round
|
parentRound := decodedExtraField.QuorumCert.ProposedBlockInfo.Round
|
||||||
round := decodedExtraField.Round
|
round := decodedExtraField.Round
|
||||||
epochStart := round - round%utils.Round(x.config.Epoch)
|
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 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 {
|
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())
|
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())
|
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,
|
// 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
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"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/log"
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Position(list []common.Address, x common.Address) int {
|
func Position(list []common.Address, x common.Address) int {
|
||||||
|
|
@ -55,51 +49,6 @@ func ExtractValidatorsFromBytes(byteValidators []byte) []int64 {
|
||||||
return validators
|
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
|
// compare 2 signers lists
|
||||||
// return true if they are same elements, otherwise return false
|
// return true if they are same elements, otherwise return false
|
||||||
func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool {
|
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)
|
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)
|
// Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions)
|
||||||
func DecodeBytesExtraFields(b []byte, val interface{}) error {
|
func DecodeBytesExtraFields(b []byte, val interface{}) error {
|
||||||
if len(b) == 0 {
|
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])
|
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
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"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) {
|
func TestCompareSignersLists(t *testing.T) {
|
||||||
list1 := []common.Address{
|
list1 := []common.Address{
|
||||||
common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) {
|
||||||
ParentHash: currentBlock.Hash(),
|
ParentHash: currentBlock.Hash(),
|
||||||
Coinbase: common.HexToAddress(blockCoinBase),
|
Coinbase: common.HexToAddress(blockCoinBase),
|
||||||
}
|
}
|
||||||
err := generateSignature(backend, header)
|
err := generateSignature(backend, adaptor, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -66,11 +66,11 @@ func TestAdaptorGetMasternodesFromCheckpointHeader(t *testing.T) {
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
headerV1 := currentBlock.Header()
|
headerV1 := currentBlock.Header()
|
||||||
headerV1.Extra = common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400")
|
headerV1.Extra = common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400")
|
||||||
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1, 0, 0)
|
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1)
|
||||||
headerV2 := currentBlock.Header()
|
headerV2 := currentBlock.Header()
|
||||||
headerV2.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(1))
|
headerV2.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(1))
|
||||||
headerV2.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c")
|
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)
|
assert.True(t, reflect.DeepEqual(masternodesV1, masternodesV2), "GetMasternodesFromCheckpointHeader in adaptor for v1 v2 not equal", "v1", masternodesV1, "v2", masternodesV2)
|
||||||
}
|
}
|
||||||
func TestAdaptorIsEpochSwitch(t *testing.T) {
|
func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
|
|
@ -79,9 +79,15 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
header := currentBlock.Header()
|
header := currentBlock.Header()
|
||||||
// v1
|
// v1
|
||||||
header.Number.SetUint64(0)
|
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)
|
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
|
// v2
|
||||||
parentBlockInfo := &utils.BlockInfo{
|
parentBlockInfo := &utils.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
|
|
@ -100,7 +106,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(1))
|
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{
|
parentBlockInfo = &utils.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: utils.Round(1),
|
Round: utils.Round(1),
|
||||||
|
|
@ -118,7 +126,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(2))
|
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{
|
parentBlockInfo = &utils.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: utils.Round(blockchain.Config().XDPoS.Epoch) - 1,
|
Round: utils.Round(blockchain.Config().XDPoS.Epoch) - 1,
|
||||||
|
|
@ -136,7 +146,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(101))
|
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{
|
parentBlockInfo = &utils.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: utils.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
Round: utils.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
||||||
|
|
@ -154,7 +166,9 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.XDPoSV2Block, big.NewInt(101))
|
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) {
|
func TestAdaptorGetMasternodesV2(t *testing.T) {
|
||||||
|
|
@ -173,6 +187,8 @@ func TestAdaptorGetMasternodesV2(t *testing.T) {
|
||||||
}
|
}
|
||||||
masternodes1 := adaptor.GetMasternodes(blockchain, currentBlock.Header())
|
masternodes1 := adaptor.GetMasternodes(blockchain, currentBlock.Header())
|
||||||
assert.Equal(t, 3, len(masternodes1))
|
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++ {
|
for blockNum = 12; blockNum < 15; blockNum++ {
|
||||||
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn)
|
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn)
|
||||||
currentBlock, err = insertBlock(blockchain, blockHeader)
|
currentBlock, err = insertBlock(blockchain, blockHeader)
|
||||||
|
|
@ -181,5 +197,46 @@ func TestAdaptorGetMasternodesV2(t *testing.T) {
|
||||||
}
|
}
|
||||||
masternodes2 := adaptor.GetMasternodes(blockchain, currentBlock.Header())
|
masternodes2 := adaptor.GetMasternodes(blockchain, currentBlock.Header())
|
||||||
assert.True(t, reflect.DeepEqual(masternodes1, masternodes2), "at block number", blockNum)
|
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
|
// Acc3 is the default account that is on the signerList
|
||||||
|
|
||||||
engine := blockchain.Engine().(*XDPoS.XDPoS)
|
engine := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
isAuthorisedMN := engine.IsAuthorisedAddress(block449.Header(), blockchain, acc3Addr)
|
isAuthorisedMN := engine.IsAuthorisedAddress(blockchain, block449.Header(), acc3Addr)
|
||||||
assert.True(t, isAuthorisedMN)
|
assert.True(t, isAuthorisedMN)
|
||||||
|
|
||||||
isAuthorisedMN = engine.IsAuthorisedAddress(block449.Header(), blockchain, acc1Addr)
|
isAuthorisedMN = engine.IsAuthorisedAddress(blockchain, block449.Header(), acc1Addr)
|
||||||
assert.False(t, isAuthorisedMN)
|
assert.False(t, isAuthorisedMN)
|
||||||
|
|
||||||
// Now, let's mine another block to trigger the GAP block signerList update
|
// 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)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthorisedMN = engine.IsAuthorisedAddress(block450.Header(), blockchain, acc3Addr)
|
isAuthorisedMN = engine.IsAuthorisedAddress(blockchain, block450.Header(), acc3Addr)
|
||||||
assert.False(t, isAuthorisedMN)
|
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)
|
assert.True(t, isAuthorisedMN)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,10 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
|
checkpointChanMsg := <-core.CheckpointCh
|
||||||
|
log.Info("[V1] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||||
|
}()
|
||||||
|
|
||||||
return blockchain, backend, currentBlock, signer
|
return blockchain, backend, currentBlock, signer
|
||||||
}
|
}
|
||||||
|
|
@ -320,6 +324,10 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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
|
return blockchain, backend, currentBlock, signer, signFn, currentForkBlock
|
||||||
}
|
}
|
||||||
|
|
@ -385,13 +393,13 @@ func createBlock(chainConfig *params.ChainConfig, startingBlock *types.Block, bl
|
||||||
return header
|
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()
|
signer, signFn, err := backends.SimulateWalletAddressAndSignFn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("Error while creating simulated wallet for generating singer address and signer fn: %v", err))
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -488,7 +496,7 @@ func createXDPoSTestBlock(bc *BlockChain, customHeader *types.Header, txs []*typ
|
||||||
Time: big.NewInt(customHeader.Number.Int64() * 10),
|
Time: big.NewInt(customHeader.Number.Int64() * 10),
|
||||||
Extra: customHeader.Extra,
|
Extra: customHeader.Extra,
|
||||||
Validator: customHeader.Validator,
|
Validator: customHeader.Validator,
|
||||||
Validators: customHeader.Validators,
|
Validators: customHeader.Validators,
|
||||||
}
|
}
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
if len(txs) == 0 {
|
if len(txs) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -352,8 +352,7 @@ func GetRewardForCheckpoint(c *XDPoS.XDPoS, chain consensus.ChainReader, header
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
header = chain.GetHeader(header.ParentHash, prevCheckpoint)
|
header = chain.GetHeader(header.ParentHash, prevCheckpoint)
|
||||||
//TODO: i think this should be c.GetMasternodesFrom...
|
masternodes := c.GetMasternodesFromCheckpointHeader(header)
|
||||||
masternodes := utils.GetMasternodesFromCheckpointHeader(header)
|
|
||||||
|
|
||||||
for i := startBlockNumber; i <= endBlockNumber; i++ {
|
for i := startBlockNumber; i <= endBlockNumber; i++ {
|
||||||
if i%common.MergeSignRange == 0 || !chain.Config().IsTIP2019(big.NewInt(int64(i))) {
|
if i%common.MergeSignRange == 0 || !chain.Config().IsTIP2019(big.NewInt(int64(i))) {
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,12 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
"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)
|
bc.reportBlock(block, nil, err)
|
||||||
return i, events, coalescedLogs, err
|
return i, events, coalescedLogs, err
|
||||||
}
|
}
|
||||||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
isEpochSwithBlock, epochNumber, err := engine.IsEpochSwitch(block.Header())
|
||||||
if err := tradingService.UpdateMediumPriceBeforeEpoch(block.NumberU64()/bc.chainConfig.XDPoS.Epoch, tradingState, statedb); err != nil {
|
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
|
return i, events, coalescedLogs, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1708,9 +1713,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty
|
||||||
stats.report(chain, i, dirty)
|
stats.report(chain, i, dirty)
|
||||||
if bc.chainConfig.XDPoS != nil {
|
if bc.chainConfig.XDPoS != nil {
|
||||||
// epoch block
|
// 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
|
CheckpointCh <- 1
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1855,8 +1864,15 @@ func (bc *BlockChain) getResultBlock(block *types.Block, verifiedM2 bool) (*Resu
|
||||||
bc.reportBlock(block, nil, err)
|
bc.reportBlock(block, nil, err)
|
||||||
return 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
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2029,7 +2045,12 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L
|
||||||
stats.report(types.Blocks{block}, 0, dirty)
|
stats.report(types.Blocks{block}, 0, dirty)
|
||||||
if bc.chainConfig.XDPoS != nil {
|
if bc.chainConfig.XDPoS != nil {
|
||||||
// epoch block
|
// 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
|
CheckpointCh <- 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,17 @@ func (b *EthApiBackend) GetVotersRewards(masternodeAddr common.Address) map[comm
|
||||||
number := block.Number().Uint64()
|
number := block.Number().Uint64()
|
||||||
engine := b.GetEngine().(*XDPoS.XDPoS)
|
engine := b.GetEngine().(*XDPoS.XDPoS)
|
||||||
foundationWalletAddr := chain.Config().XDPoS.FoudationWalletAddr
|
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)
|
lastCheckpointBlock := chain.GetBlockByNumber(lastCheckpointNumber)
|
||||||
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
|
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ func New(ctx *node.ServiceContext, config *Config, XDCXServ *XDCx.XDCX, lendingS
|
||||||
return block, false, err
|
return block, false, err
|
||||||
}
|
}
|
||||||
header := block.Header()
|
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 {
|
if err != nil || sighash == nil {
|
||||||
log.Error("Can't get signature hash of m2", "sighash", sighash, "err", err)
|
log.Error("Can't get signature hash of m2", "sighash", sighash, "err", err)
|
||||||
return block, false, err
|
return block, false, err
|
||||||
|
|
@ -296,7 +296,7 @@ func New(ctx *node.ServiceContext, config *Config, XDCXServ *XDCx.XDCX, lendingS
|
||||||
// not genesis block
|
// not genesis block
|
||||||
header = parentHeader
|
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.
|
// APIs returns the collection of RPC services the ethereum package offers.
|
||||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||||
func (s *Ethereum) APIs() []rpc.API {
|
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
|
// Append any APIs exposed explicitly by the consensus engine
|
||||||
apis = append(apis, s.engine.APIs(s.BlockChain())...)
|
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
|
//check if miner's wallet is in set of validators
|
||||||
c := s.engine.(*XDPoS.XDPoS)
|
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 {
|
if !authorized {
|
||||||
//This miner doesn't belong to set of validators
|
//This miner doesn't belong to set of validators
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
|
"github.com/XinFinOrg/XDPoSChain/XDCxlending/lendingstate"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate"
|
"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.
|
// PublicBlockChainAPI provides an API to access the Ethereum blockchain.
|
||||||
// It offers only methods that operate on public data that is freely available to anyone.
|
// It offers only methods that operate on public data that is freely available to anyone.
|
||||||
type PublicBlockChainAPI struct {
|
type PublicBlockChainAPI struct {
|
||||||
b Backend
|
b Backend
|
||||||
|
chainReader consensus.ChainReader
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
|
// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
|
||||||
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
|
func NewPublicBlockChainAPI(b Backend, chainReader consensus.ChainReader) *PublicBlockChainAPI {
|
||||||
return &PublicBlockChainAPI{b}
|
return &PublicBlockChainAPI{
|
||||||
|
b,
|
||||||
|
chainReader,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockNumber returns the block number of the chain head.
|
// 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 {
|
if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok {
|
||||||
// Get block epoc latest.
|
// Get block epoc latest.
|
||||||
lastCheckpointNumber := prevBlockNumber - (prevBlockNumber % s.b.ChainConfig().XDPoS.Epoch)
|
return engine.GetMasternodesByNumber(s.chainReader, prevBlockNumber), nil
|
||||||
prevCheckpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(lastCheckpointNumber))
|
|
||||||
if prevCheckpointBlock != nil {
|
|
||||||
masternodes = engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), curBlockNumber, s.b.ChainConfig().XDPoS.Epoch)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log.Error("Undefined XDPoS consensus engine")
|
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
|
// Second, Find candidates that have masternode status
|
||||||
if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok {
|
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 {
|
if len(masternodes) == 0 {
|
||||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
||||||
result[fieldSuccess] = false
|
result[fieldSuccess] = false
|
||||||
|
|
@ -902,7 +903,7 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch
|
||||||
|
|
||||||
// Second, Find candidates that have masternode status
|
// Second, Find candidates that have masternode status
|
||||||
if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok {
|
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 {
|
if len(masternodes) == 0 {
|
||||||
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
log.Error("Failed to get masternodes", "err", err, "len(masternodes)", len(masternodes), "blockNum", header.Number.Uint64())
|
||||||
result[fieldSuccess] = false
|
result[fieldSuccess] = false
|
||||||
|
|
@ -965,21 +966,22 @@ func (s *PublicBlockChainAPI) GetCandidates(ctx context.Context, epoch rpc.Epoch
|
||||||
// GetPreviousCheckpointFromEpoch returns header of the previous checkpoint
|
// GetPreviousCheckpointFromEpoch returns header of the previous checkpoint
|
||||||
func (s *PublicBlockChainAPI) GetPreviousCheckpointFromEpoch(ctx context.Context, epochNum rpc.EpochNumber) (rpc.BlockNumber, rpc.EpochNumber) {
|
func (s *PublicBlockChainAPI) GetPreviousCheckpointFromEpoch(ctx context.Context, epochNum rpc.EpochNumber) (rpc.BlockNumber, rpc.EpochNumber) {
|
||||||
var checkpointNumber uint64
|
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 {
|
if epochNum == rpc.LatestEpochNumber {
|
||||||
blockNumer := s.b.CurrentBlock().Number().Uint64()
|
checkpointNumber = currentCheckpointNumber
|
||||||
diff := blockNumer % epoch
|
epochNum = rpc.EpochNumber(epochNumber)
|
||||||
// checkpoint number
|
|
||||||
checkpointNumber = blockNumer - diff
|
|
||||||
epochNum = rpc.EpochNumber(checkpointNumber / epoch)
|
|
||||||
if diff > 0 {
|
|
||||||
epochNum += 1
|
|
||||||
}
|
|
||||||
} else if epochNum < 2 {
|
} else if epochNum < 2 {
|
||||||
checkpointNumber = 0
|
checkpointNumber = 0
|
||||||
} else {
|
} 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
|
return rpc.BlockNumber(checkpointNumber), epochNum
|
||||||
}
|
}
|
||||||
|
|
@ -1301,7 +1303,11 @@ func (s *PublicBlockChainAPI) findNearestSignedBlock(ctx context.Context, b *typ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get block epoc latest
|
// 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))
|
checkpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
||||||
|
|
||||||
if checkpointBlock != nil {
|
if checkpointBlock != nil {
|
||||||
|
|
@ -1385,13 +1391,9 @@ func (s *PublicBlockChainAPI) getSigners(ctx context.Context, block *types.Block
|
||||||
var err error
|
var err error
|
||||||
var filterSigners []common.Address
|
var filterSigners []common.Address
|
||||||
var signers []common.Address
|
var signers []common.Address
|
||||||
blockNumber := block.Number().Uint64()
|
|
||||||
|
|
||||||
// Get block epoc latest.
|
masternodes := engine.GetMasternodes(s.chainReader, block.Header())
|
||||||
checkpointNumber := blockNumber - (blockNumber % s.b.ChainConfig().XDPoS.Epoch)
|
|
||||||
checkpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(checkpointNumber))
|
|
||||||
|
|
||||||
masternodes := engine.GetMasternodesFromCheckpointHeader(checkpointBlock.Header(), blockNumber, s.b.ChainConfig().XDPoS.Epoch)
|
|
||||||
signers, err = GetSignersFromBlocks(s.b, block.NumberU64(), block.Hash(), masternodes)
|
signers, err = GetSignersFromBlocks(s.b, block.NumberU64(), block.Hash(), masternodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Fail to get signers from block signer SC.", "error", err)
|
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)
|
GetOrderNonce(address common.Hash) (uint64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAPIs(apiBackend Backend) []rpc.API {
|
func GetAPIs(apiBackend Backend, chainReader consensus.ChainReader) []rpc.API {
|
||||||
nonceLock := new(AddrLocker)
|
nonceLock := new(AddrLocker)
|
||||||
return []rpc.API{
|
return []rpc.API{
|
||||||
{
|
{
|
||||||
|
|
@ -108,7 +108,7 @@ func GetAPIs(apiBackend Backend) []rpc.API {
|
||||||
}, {
|
}, {
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPublicBlockChainAPI(apiBackend),
|
Service: NewPublicBlockChainAPI(apiBackend, chainReader),
|
||||||
Public: true,
|
Public: true,
|
||||||
}, {
|
}, {
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ func (s *LightDummyAPI) Mining() bool {
|
||||||
// APIs returns the collection of RPC services the ethereum package offers.
|
// APIs returns the collection of RPC services the ethereum package offers.
|
||||||
// NOTE, some of these services probably need to be moved to somewhere else.
|
// NOTE, some of these services probably need to be moved to somewhere else.
|
||||||
func (s *LightEthereum) APIs() []rpc.API {
|
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",
|
Namespace: "eth",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,11 @@ func (self *worker) wait() {
|
||||||
}
|
}
|
||||||
if work.config.XDPoS != nil {
|
if work.config.XDPoS != nil {
|
||||||
// epoch block
|
// 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
|
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())
|
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 {
|
if !authorized {
|
||||||
valid := false
|
valid := false
|
||||||
masternodes := c.GetMasternodes(self.chain, block.Header())
|
masternodes := c.GetMasternodes(self.chain, block.Header())
|
||||||
|
|
@ -635,13 +639,19 @@ func (self *worker) commitNewWork() {
|
||||||
lendingFinalizedTradeTransaction *types.Transaction
|
lendingFinalizedTradeTransaction *types.Transaction
|
||||||
)
|
)
|
||||||
feeCapacity := state.GetTRC21FeeCapacityFromStateWithCache(parent.Root(), work.state)
|
feeCapacity := state.GetTRC21FeeCapacityFromStateWithCache(parent.Root(), work.state)
|
||||||
if self.config.XDPoS != nil && header.Number.Uint64()%self.config.XDPoS.Epoch != 0 {
|
if self.config.XDPoS != nil {
|
||||||
pending, err := self.eth.TxPool().Pending()
|
isEpochSwitchBlock, _, err := self.engine.(*XDPoS.XDPoS).IsEpochSwitch(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to fetch pending transactions", "err", err)
|
log.Error("[commitNewWork] fail to check if block is epoch switch block when fetching pending transactions", "BlockNum", header.Number, "Hash", header.Hash())
|
||||||
return
|
}
|
||||||
|
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 {
|
if atomic.LoadInt32(&self.mining) == 1 {
|
||||||
wallet, err := self.eth.AccountManager().Find(accounts.Account{Address: self.coinbase})
|
wallet, err := self.eth.AccountManager().Find(accounts.Account{Address: self.coinbase})
|
||||||
|
|
@ -653,16 +663,20 @@ func (self *worker) commitNewWork() {
|
||||||
XDCX := self.eth.GetXDCX()
|
XDCX := self.eth.GetXDCX()
|
||||||
XDCXLending := self.eth.GetXDCXLending()
|
XDCXLending := self.eth.GetXDCXLending()
|
||||||
if XDCX != nil && header.Number.Uint64() > self.config.XDPoS.Epoch {
|
if XDCX != nil && header.Number.Uint64() > self.config.XDPoS.Epoch {
|
||||||
if header.Number.Uint64()%self.config.XDPoS.Epoch == 0 {
|
isEpochSwitchBlock, epochNumber, err := self.engine.(*XDPoS.XDPoS).IsEpochSwitch(header)
|
||||||
err := XDCX.UpdateMediumPriceBeforeEpoch(header.Number.Uint64()/self.config.XDPoS.Epoch, work.tradingState, work.state)
|
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 {
|
if err != nil {
|
||||||
log.Error("Fail when update medium price last epoch", "error", err)
|
log.Error("Fail when update medium price last epoch", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
// won't grasp tx at checkpoint
|
// won't grasp tx at checkpoint
|
||||||
//https://github.com/XinFinOrg/XDPoSChain-v1/pull/416
|
//https://github.com/XinFinOrg/XDPoSChain-v1/pull/416
|
||||||
if header.Number.Uint64()%self.config.XDPoS.Epoch != 0 {
|
|
||||||
log.Debug("Start processing order pending")
|
log.Debug("Start processing order pending")
|
||||||
tradingOrderPending, _ := self.eth.OrderPool().Pending()
|
tradingOrderPending, _ := self.eth.OrderPool().Pending()
|
||||||
log.Debug("Start processing order pending", "len", len(tradingOrderPending))
|
log.Debug("Start processing order pending", "len", len(tradingOrderPending))
|
||||||
|
|
@ -680,6 +694,7 @@ func (self *worker) commitNewWork() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tradingTxMatches) > 0 {
|
if len(tradingTxMatches) > 0 {
|
||||||
txMatchBatch := &tradingstate.TxMatchBatch{
|
txMatchBatch := &tradingstate.TxMatchBatch{
|
||||||
Data: tradingTxMatches,
|
Data: tradingTxMatches,
|
||||||
|
|
@ -1062,10 +1077,16 @@ func (env *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Ad
|
||||||
}
|
}
|
||||||
go func(logs []*types.Log, tcount int) {
|
go func(logs []*types.Log, tcount int) {
|
||||||
if len(logs) > 0 {
|
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 {
|
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)
|
}(cpy, env.tcount)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue