mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
Multi config bug fix (#216)
* refactor multi config remove pool cleaner correct message and log level
This commit is contained in:
parent
96339ec3ba
commit
c4f9a552e5
23 changed files with 319 additions and 200 deletions
|
|
@ -346,7 +346,8 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
|
||||||
for range core.CheckpointCh {
|
for range core.CheckpointCh {
|
||||||
log.Info("Checkpoint!!! It's time to reconcile node's state...")
|
log.Info("Checkpoint!!! It's time to reconcile node's state...")
|
||||||
log.Info("Update consensus parameters")
|
log.Info("Update consensus parameters")
|
||||||
engine.UpdateParams()
|
chain := ethereum.BlockChain()
|
||||||
|
engine.UpdateParams(chain.CurrentHeader())
|
||||||
if common.IsTestnet {
|
if common.IsTestnet {
|
||||||
ok, err = ethereum.ValidateMasternodeTestnet()
|
ok, err = ethereum.ValidateMasternodeTestnet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ExtraFieldCheck = false
|
ExtraFieldCheck = true
|
||||||
SkipExtraFieldCheck = true
|
SkipExtraFieldCheck = false
|
||||||
)
|
)
|
||||||
|
|
||||||
func (x *XDPoS) SigHash(header *types.Header) (hash common.Hash) {
|
func (x *XDPoS) SigHash(header *types.Header) (hash common.Hash) {
|
||||||
|
|
@ -79,7 +79,7 @@ func (x *XDPoS) SubscribeForensicsEvent(ch chan<- types.ForensicsEvent) event.Su
|
||||||
// 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 {
|
func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS {
|
||||||
log.Info("[New] initial conensus engines")
|
log.Info("[New] initialise consensus engines")
|
||||||
// Set any missing consensus parameters to their defaults
|
// Set any missing consensus parameters to their defaults
|
||||||
if config.Epoch == 0 {
|
if config.Epoch == 0 {
|
||||||
config.Epoch = utils.EpochLength
|
config.Epoch = utils.EpochLength
|
||||||
|
|
@ -88,9 +88,9 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS {
|
||||||
// For testing and testing project, default to mainnet config
|
// For testing and testing project, default to mainnet config
|
||||||
if config.V2 == nil {
|
if config.V2 == nil {
|
||||||
config.V2 = ¶ms.V2{
|
config.V2 = ¶ms.V2{
|
||||||
FirstSwitchBlock: params.MainnetV2Configs[0].SwitchBlock,
|
SwitchBlock: params.XDCMainnetChainConfig.XDPoS.V2.SwitchBlock,
|
||||||
CurrentConfig: params.MainnetV2Configs[0],
|
CurrentConfig: params.MainnetV2Configs[0],
|
||||||
AllConfigs: params.MainnetV2Configs,
|
AllConfigs: params.MainnetV2Configs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,8 +145,14 @@ func NewFaker(db ethdb.Database, chainConfig *params.ChainConfig) *XDPoS {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset parameters after checkpoint due to config may change
|
// Reset parameters after checkpoint due to config may change
|
||||||
func (x *XDPoS) UpdateParams() {
|
func (x *XDPoS) UpdateParams(header *types.Header) {
|
||||||
x.EngineV2.UpdateParams()
|
switch x.config.BlockConsensusVersion(header.Number, header.Extra, ExtraFieldCheck) {
|
||||||
|
case params.ConsensusEngineVersion2:
|
||||||
|
x.EngineV2.UpdateParams(header)
|
||||||
|
return
|
||||||
|
default: // Default "v1"
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS) Initial(chain consensus.ChainReader, header *types.Header) error {
|
func (x *XDPoS) Initial(chain consensus.ChainReader, header *types.Header) error {
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *
|
||||||
timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout
|
timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout
|
||||||
|
|
||||||
engine.periodicJob()
|
engine.periodicJob()
|
||||||
config.BuildConfigIndex()
|
config.V2.BuildConfigIndex()
|
||||||
|
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +131,13 @@ signing. It is the hash of the entire header apart from the 65 byte signature
|
||||||
contained at the end of the extra data.
|
contained at the end of the extra data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (x *XDPoS_v2) UpdateParams() {
|
func (x *XDPoS_v2) UpdateParams(header *types.Header) {
|
||||||
|
_, round, _, err := x.getExtraFields(header)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[UpdateParams] retrieve round failed", "block", header.Number.Uint64(), "err", err)
|
||||||
|
}
|
||||||
|
x.config.V2.UpdateConfig(uint64(round))
|
||||||
|
|
||||||
// Setup timeoutTimer
|
// Setup timeoutTimer
|
||||||
duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
||||||
x.timeoutWorker.SetTimeoutDuration(duration)
|
x.timeoutWorker.SetTimeoutDuration(duration)
|
||||||
|
|
@ -163,7 +169,7 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
||||||
var quorumCert *types.QuorumCert
|
var quorumCert *types.QuorumCert
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if header.Number.Int64() == x.config.V2.FirstSwitchBlock.Int64() {
|
if header.Number.Int64() == x.config.V2.SwitchBlock.Int64() {
|
||||||
log.Info("[initial] highest QC for consensus v2 first block")
|
log.Info("[initial] highest QC for consensus v2 first block")
|
||||||
blockInfo := &types.BlockInfo{
|
blockInfo := &types.BlockInfo{
|
||||||
Hash: header.Hash(),
|
Hash: header.Hash(),
|
||||||
|
|
@ -193,13 +199,13 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial first v2 snapshot
|
// Initial first v2 snapshot
|
||||||
lastGapNum := x.config.V2.FirstSwitchBlock.Uint64() - x.config.Gap
|
lastGapNum := x.config.V2.SwitchBlock.Uint64() - x.config.Gap
|
||||||
lastGapHeader := chain.GetHeaderByNumber(lastGapNum)
|
lastGapHeader := chain.GetHeaderByNumber(lastGapNum)
|
||||||
|
|
||||||
snap, _ := loadSnapshot(x.db, lastGapHeader.Hash())
|
snap, _ := loadSnapshot(x.db, lastGapHeader.Hash())
|
||||||
|
|
||||||
if snap == nil {
|
if snap == nil {
|
||||||
checkpointHeader := chain.GetHeaderByNumber(x.config.V2.FirstSwitchBlock.Uint64())
|
checkpointHeader := chain.GetHeaderByNumber(x.config.V2.SwitchBlock.Uint64())
|
||||||
|
|
||||||
log.Info("[initial] init first snapshot")
|
log.Info("[initial] init first snapshot")
|
||||||
_, _, masternodes, err := x.getExtraFields(checkpointHeader)
|
_, _, masternodes, err := x.getExtraFields(checkpointHeader)
|
||||||
|
|
@ -246,7 +252,9 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
||||||
}
|
}
|
||||||
|
|
||||||
waitedTime := time.Now().Unix() - parent.Time.Int64()
|
waitedTime := time.Now().Unix() - parent.Time.Int64()
|
||||||
if waitedTime < int64(x.config.V2.CurrentConfig.MinePeriod) {
|
_, parentRound, _, err := x.getExtraFields(parent)
|
||||||
|
minePeriod := x.config.V2.Config(uint64(parentRound) + 1).MinePeriod // plus 1 means current block
|
||||||
|
if waitedTime < int64(minePeriod) {
|
||||||
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.CurrentConfig.MinePeriod, "waitedTime", waitedTime)
|
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.CurrentConfig.MinePeriod, "waitedTime", waitedTime)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
@ -718,7 +726,7 @@ func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, block
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch block is a v1 block, there is no valid extra to decode, nor its round
|
// Switch block is a v1 block, there is no valid extra to decode, nor its round
|
||||||
if blockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
if blockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||||
if blockInfo.Round != 0 {
|
if blockInfo.Round != 0 {
|
||||||
log.Error("[VerifyBlockInfo] Switch block round is not 0", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number)
|
log.Error("[VerifyBlockInfo] Switch block round is not 0", "BlockInfoHash", blockInfo.Hash.Hex(), "BlockInfoNum", blockInfo.Number, "BlockInfoRound", blockInfo.Round, "blockHeaderNum", blockHeader.Number)
|
||||||
return fmt.Errorf("[VerifyBlockInfo] switch block round have to be 0")
|
return fmt.Errorf("[VerifyBlockInfo] switch block round have to be 0")
|
||||||
|
|
@ -751,6 +759,12 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
4. Verify gapNumber = epochSwitchNumber - epochSwitchNumber%Epoch - Gap
|
4. Verify gapNumber = epochSwitchNumber - epochSwitchNumber%Epoch - Gap
|
||||||
5. Verify blockInfo
|
5. Verify blockInfo
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if quorumCert == nil {
|
||||||
|
log.Warn("[verifyQC] QC is Nil")
|
||||||
|
return utils.ErrInvalidQC
|
||||||
|
}
|
||||||
|
|
||||||
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, parentHeader, quorumCert.ProposedBlockInfo.Hash)
|
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, parentHeader, quorumCert.ProposedBlockInfo.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
|
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
|
||||||
|
|
@ -763,13 +777,13 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if quorumCert == nil {
|
|
||||||
log.Warn("[verifyQC] QC is Nil")
|
qcRound := quorumCert.ProposedBlockInfo.Round
|
||||||
return utils.ErrInvalidQC
|
certThreshold := x.config.V2.Config(uint64(qcRound)).CertThreshold
|
||||||
} else if (quorumCert.ProposedBlockInfo.Number.Uint64() > x.config.V2.FirstSwitchBlock.Uint64()) && (signatures == nil || (len(signatures) < x.config.V2.CurrentConfig.CertThreshold)) {
|
if (qcRound > 0) && (signatures == nil || (len(signatures) < certThreshold)) {
|
||||||
//First V2 Block QC, QC Signatures is initial nil
|
//First V2 Block QC, QC Signatures is initial nil
|
||||||
log.Warn("[verifyHeader] Invalid QC Signature is nil or empty", "QC", quorumCert, "QCNumber", quorumCert.ProposedBlockInfo.Number, "Signatures len", len(signatures))
|
log.Warn("[verifyHeader] Invalid QC Signature is nil or less then config", "QC", quorumCert, "QCNumber", quorumCert.ProposedBlockInfo.Number, "Signatures len", len(signatures), "CertThreshold", certThreshold)
|
||||||
return utils.ErrInvalidQC
|
return utils.ErrInvalidQCSignatures
|
||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
|
|
@ -798,7 +812,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
log.Info("[verifyQC] time verify message signatures of qc", "elapsed", elapsed)
|
log.Debug("[verifyQC] time verify message signatures of qc", "elapsed", elapsed)
|
||||||
if haveError != nil {
|
if haveError != nil {
|
||||||
return haveError
|
return haveError
|
||||||
}
|
}
|
||||||
|
|
@ -826,7 +840,7 @@ func (x *XDPoS_v2) processQC(blockChainReader consensus.ChainReader, incomingQuo
|
||||||
log.Error("[processQC] Block not found using the QC", "quorumCert.ProposedBlockInfo.Hash", incomingQuorumCert.ProposedBlockInfo.Hash, "incomingQuorumCert.ProposedBlockInfo.Number", incomingQuorumCert.ProposedBlockInfo.Number)
|
log.Error("[processQC] Block not found using the QC", "quorumCert.ProposedBlockInfo.Hash", incomingQuorumCert.ProposedBlockInfo.Hash, "incomingQuorumCert.ProposedBlockInfo.Number", incomingQuorumCert.ProposedBlockInfo.Number)
|
||||||
return fmt.Errorf("block not found, number: %v, hash: %v", incomingQuorumCert.ProposedBlockInfo.Number, incomingQuorumCert.ProposedBlockInfo.Hash)
|
return fmt.Errorf("block not found, number: %v, hash: %v", incomingQuorumCert.ProposedBlockInfo.Number, incomingQuorumCert.ProposedBlockInfo.Hash)
|
||||||
}
|
}
|
||||||
if proposedBlockHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) > 0 {
|
if proposedBlockHeader.Number.Cmp(x.config.V2.SwitchBlock) > 0 {
|
||||||
// Extra field contain parent information
|
// Extra field contain parent information
|
||||||
proposedBlockQuorumCert, round, _, err := x.getExtraFields(proposedBlockHeader)
|
proposedBlockQuorumCert, round, _, err := x.getExtraFields(proposedBlockHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -882,7 +896,7 @@ func (x *XDPoS_v2) getSyncInfo() *types.SyncInfo {
|
||||||
//Find parent and grandparent, check round number, if so, commit grandparent(grandGrandParent of currentBlock)
|
//Find parent and grandparent, check round number, if so, commit grandparent(grandGrandParent of currentBlock)
|
||||||
func (x *XDPoS_v2) commitBlocks(blockChainReader consensus.ChainReader, proposedBlockHeader *types.Header, proposedBlockRound *types.Round, incomingQc *types.QuorumCert) (bool, error) {
|
func (x *XDPoS_v2) commitBlocks(blockChainReader consensus.ChainReader, proposedBlockHeader *types.Header, proposedBlockRound *types.Round, incomingQc *types.QuorumCert) (bool, error) {
|
||||||
// XDPoS v1.0 switch to v2.0, skip commit
|
// XDPoS v1.0 switch to v2.0, skip commit
|
||||||
if big.NewInt(0).Sub(proposedBlockHeader.Number, big.NewInt(2)).Cmp(x.config.V2.FirstSwitchBlock) <= 0 {
|
if big.NewInt(0).Sub(proposedBlockHeader.Number, big.NewInt(2)).Cmp(x.config.V2.SwitchBlock) <= 0 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
// Find the last two parent block and check their rounds are the continuous
|
// Find the last two parent block and check their rounds are the continuous
|
||||||
|
|
@ -959,7 +973,7 @@ func (x *XDPoS_v2) calcMasternodes(chain consensus.ChainReader, blockNum *big.In
|
||||||
}
|
}
|
||||||
candidates := snap.NextEpochMasterNodes
|
candidates := snap.NextEpochMasterNodes
|
||||||
|
|
||||||
if blockNum.Uint64() == x.config.V2.FirstSwitchBlock.Uint64()+1 {
|
if blockNum.Uint64() == x.config.V2.SwitchBlock.Uint64()+1 {
|
||||||
log.Info("[calcMasternodes] examing first v2 block")
|
log.Info("[calcMasternodes] examing first v2 block")
|
||||||
return candidates, []common.Address{}, nil
|
return candidates, []common.Address{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,9 @@ func (x *XDPoS_v2) getEpochSwitchInfo(chain consensus.ChainReader, header *types
|
||||||
|
|
||||||
// IsEpochSwitchAtRound() is used by miner to check whether it mines a block in the same epoch with parent
|
// IsEpochSwitchAtRound() is used by miner to check whether it mines a block in the same epoch with parent
|
||||||
func (x *XDPoS_v2) isEpochSwitchAtRound(round types.Round, parentHeader *types.Header) (bool, uint64, error) {
|
func (x *XDPoS_v2) isEpochSwitchAtRound(round types.Round, parentHeader *types.Header) (bool, uint64, error) {
|
||||||
epochNum := x.config.V2.FirstSwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
|
epochNum := x.config.V2.SwitchBlock.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 parentHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
if parentHeader.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||||
return true, epochNum, nil
|
return true, epochNum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,13 +111,13 @@ func (x *XDPoS_v2) GetCurrentEpochSwitchBlock(chain consensus.ChainReader, block
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCheckpointNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64()
|
currentCheckpointNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64()
|
||||||
epochNum := x.config.V2.FirstSwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
||||||
return currentCheckpointNumber, epochNum, nil
|
return currentCheckpointNumber, epochNum, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
||||||
// Return true directly if we are examing the last v1 block. This could happen if the calling function is examing parent block
|
// Return true directly if we are examing the last v1 block. This could happen if the calling function is examing parent block
|
||||||
if header.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||||
log.Info("[IsEpochSwitch] examing last v1 block")
|
log.Info("[IsEpochSwitch] examing last v1 block")
|
||||||
return true, header.Number.Uint64() / x.config.Epoch, nil
|
return true, header.Number.Uint64() / x.config.Epoch, nil
|
||||||
}
|
}
|
||||||
|
|
@ -129,9 +129,9 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
||||||
}
|
}
|
||||||
parentRound := quorumCert.ProposedBlockInfo.Round
|
parentRound := quorumCert.ProposedBlockInfo.Round
|
||||||
epochStartRound := round - round%types.Round(x.config.Epoch)
|
epochStartRound := round - round%types.Round(x.config.Epoch)
|
||||||
epochNum := x.config.V2.FirstSwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
|
epochNum := x.config.V2.SwitchBlock.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 quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
if quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||||
log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
|
log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
|
||||||
return true, epochNum, nil
|
return true, epochNum, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,14 @@ func (x *XDPoS_v2) timeoutHandler(blockChainReader consensus.ChainReader, timeou
|
||||||
log.Debug("[timeoutHandler] collect timeout", "number", numberOfTimeoutsInPool)
|
log.Debug("[timeoutHandler] collect timeout", "number", numberOfTimeoutsInPool)
|
||||||
|
|
||||||
// Threshold reached
|
// Threshold reached
|
||||||
isThresholdReached := numberOfTimeoutsInPool >= x.config.V2.CurrentConfig.CertThreshold
|
certThreshold := x.config.V2.Config(uint64(x.currentRound)).CertThreshold
|
||||||
|
isThresholdReached := numberOfTimeoutsInPool >= certThreshold
|
||||||
if isThresholdReached {
|
if isThresholdReached {
|
||||||
log.Info(fmt.Sprintf("Timeout pool threashold reached: %v, number of items in the pool: %v", isThresholdReached, numberOfTimeoutsInPool))
|
log.Info(fmt.Sprintf("Timeout pool threashold reached: %v, number of items in the pool: %v", isThresholdReached, numberOfTimeoutsInPool))
|
||||||
err := x.onTimeoutPoolThresholdReached(blockChainReader, pooledTimeouts, timeout, timeout.GapNumber)
|
err := x.onTimeoutPoolThresholdReached(blockChainReader, pooledTimeouts, timeout, timeout.GapNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// clean up timeout message, regardless its GapNumber or round
|
|
||||||
x.timeoutPool.Clear()
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -82,6 +81,11 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
- Use the above public key to find out the xdc address
|
- Use the above public key to find out the xdc address
|
||||||
- Use the above xdc address to check against the master node list from step 1(For the received TC epoch)
|
- Use the above xdc address to check against the master node list from step 1(For the received TC epoch)
|
||||||
*/
|
*/
|
||||||
|
if timeoutCert == nil || timeoutCert.Signatures == nil {
|
||||||
|
log.Warn("[verifyTC] TC or TC signatures is Nil")
|
||||||
|
return utils.ErrInvalidTC
|
||||||
|
}
|
||||||
|
|
||||||
snap, err := x.getSnapshot(chain, timeoutCert.GapNumber, true)
|
snap, err := x.getSnapshot(chain, timeoutCert.GapNumber, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyTC] Fail to get snapshot when verifying TC!", "TCGapNumber", timeoutCert.GapNumber)
|
log.Error("[verifyTC] Fail to get snapshot when verifying TC!", "TCGapNumber", timeoutCert.GapNumber)
|
||||||
|
|
@ -92,16 +96,21 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
return fmt.Errorf("Empty master node lists from snapshot")
|
return fmt.Errorf("Empty master node lists from snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeoutCert == nil {
|
signatures, duplicates := UniqueSignatures(timeoutCert.Signatures)
|
||||||
log.Warn("[verifyTC] TC is Nil")
|
if len(duplicates) != 0 {
|
||||||
return utils.ErrInvalidTC
|
for _, d := range duplicates {
|
||||||
} else if timeoutCert.Signatures == nil || (len(timeoutCert.Signatures) < x.config.V2.CurrentConfig.CertThreshold) {
|
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
||||||
log.Warn("[verifyTC] Invalid TC Signature is nil or empty", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures))
|
}
|
||||||
return utils.ErrInvalidTC
|
}
|
||||||
|
|
||||||
|
certThreshold := x.config.V2.Config(uint64(timeoutCert.Round)).CertThreshold
|
||||||
|
if len(signatures) < certThreshold {
|
||||||
|
log.Warn("[verifyTC] Invalid TC Signature is nil or empty", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures), "CertThreshold", certThreshold)
|
||||||
|
return utils.ErrInvalidTCSignatures
|
||||||
}
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(timeoutCert.Signatures))
|
wg.Add(len(signatures))
|
||||||
var haveError error
|
var haveError error
|
||||||
|
|
||||||
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
|
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
|
||||||
|
|
@ -109,17 +118,17 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
GapNumber: timeoutCert.GapNumber,
|
GapNumber: timeoutCert.GapNumber,
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, signature := range timeoutCert.Signatures {
|
for _, signature := range signatures {
|
||||||
go func(sig types.Signature) {
|
go func(sig types.Signature) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
verified, _, err := x.verifyMsgSignature(signedTimeoutObj, sig, snap.NextEpochMasterNodes)
|
verified, _, err := x.verifyMsgSignature(signedTimeoutObj, sig, snap.NextEpochMasterNodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyTC] Error while verfying TC message signatures", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures), "Error", err)
|
log.Error("[verifyTC] Error while verfying TC message signatures", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures), "Error", err)
|
||||||
haveError = fmt.Errorf("Error while verfying TC message signatures")
|
haveError = fmt.Errorf("Error while verfying TC message signatures")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !verified {
|
if !verified {
|
||||||
log.Warn("[verifyTC] Signature not verified doing TC verification", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures))
|
log.Warn("[verifyTC] Signature not verified doing TC verification", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures))
|
||||||
haveError = fmt.Errorf("Fail to verify TC due to signature mis-match")
|
haveError = fmt.Errorf("Fail to verify TC due to signature mis-match")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ func (x *XDPoS_v2) getExtraFields(header *types.Header) (*types.QuorumCert, type
|
||||||
var masternodes []common.Address
|
var masternodes []common.Address
|
||||||
|
|
||||||
// last v1 block
|
// last v1 block
|
||||||
if header.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||||
masternodes = decodeMasternodesFromHeaderExtra(header)
|
masternodes = decodeMasternodesFromHeaderExtra(header)
|
||||||
return nil, types.Round(0), masternodes, nil
|
return nil, types.Round(0), masternodes, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
|
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
|
||||||
return consensus.ErrUnknownAncestor
|
return consensus.ErrUnknownAncestor
|
||||||
}
|
}
|
||||||
if parent.Number.Uint64() > x.config.V2.FirstSwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.CurrentConfig.MinePeriod) > header.Time.Uint64() {
|
if parent.Number.Uint64() > x.config.V2.SwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.CurrentConfig.MinePeriod) > header.Time.Uint64() {
|
||||||
return utils.ErrInvalidTimestamp
|
return utils.ErrInvalidTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,8 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
|
||||||
go x.ForensicsProcessor.DetectEquivocationInVotePool(voteMsg, x.votePool)
|
go x.ForensicsProcessor.DetectEquivocationInVotePool(voteMsg, x.votePool)
|
||||||
go x.ForensicsProcessor.ProcessVoteEquivocation(chain, x, voteMsg)
|
go x.ForensicsProcessor.ProcessVoteEquivocation(chain, x, voteMsg)
|
||||||
|
|
||||||
thresholdReached := numberOfVotesInPool >= x.config.V2.CurrentConfig.CertThreshold
|
certThreshold := x.config.V2.Config(uint64(voteMsg.ProposedBlockInfo.Round)).CertThreshold
|
||||||
|
thresholdReached := numberOfVotesInPool >= certThreshold
|
||||||
if thresholdReached {
|
if thresholdReached {
|
||||||
log.Info(fmt.Sprintf("[voteHandler] Vote pool threashold reached: %v, number of items in the pool: %v", thresholdReached, numberOfVotesInPool))
|
log.Info(fmt.Sprintf("[voteHandler] Vote pool threashold reached: %v, number of items in the pool: %v", thresholdReached, numberOfVotesInPool))
|
||||||
|
|
||||||
|
|
@ -113,46 +114,48 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole
|
||||||
// Filter out non-Master nodes signatures
|
// Filter out non-Master nodes signatures
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(pooledVotes))
|
wg.Add(len(pooledVotes))
|
||||||
signatureSlice := make([]types.Signature, len(pooledVotes))
|
signatures := make([]types.Signature, len(pooledVotes))
|
||||||
counter := 0
|
counter := 0
|
||||||
for h, vote := range pooledVotes {
|
for h, vote := range pooledVotes {
|
||||||
go func(hash common.Hash, v *types.Vote, i int) {
|
go func(hash common.Hash, v *types.Vote, i int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
verified, _, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
|
signedVote := types.VoteSigHash(&types.VoteForSign{
|
||||||
ProposedBlockInfo: v.ProposedBlockInfo,
|
ProposedBlockInfo: v.ProposedBlockInfo,
|
||||||
GapNumber: v.GapNumber,
|
GapNumber: v.GapNumber,
|
||||||
}), v.Signature, masternodes)
|
})
|
||||||
|
verified, _, err := x.verifyMsgSignature(signedVote, v.Signature, masternodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "Error", err.Error())
|
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "error", err.Error())
|
||||||
} else if !verified {
|
} else if !verified {
|
||||||
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "verified", verified)
|
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "verified", verified)
|
||||||
} else {
|
} else {
|
||||||
signatureSlice[i] = v.Signature
|
signatures[i] = v.Signature
|
||||||
}
|
}
|
||||||
}(h, vote.(*types.Vote), counter)
|
}(h, vote.(*types.Vote), counter)
|
||||||
counter++
|
counter++
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
log.Info("[onVotePoolThresholdReached] verify message signatures of vote pool took", "elapsed", elapsed)
|
log.Debug("[onVotePoolThresholdReached] verify message signatures of vote pool took", "elapsed", elapsed)
|
||||||
|
|
||||||
// The signature list may contain empty entey. we only care the ones with values
|
// The signature list may contain empty entey. we only care the ones with values
|
||||||
var validSignatureSlice []types.Signature
|
var validSignatures []types.Signature
|
||||||
for _, v := range signatureSlice {
|
for _, v := range signatures {
|
||||||
if len(v) != 0 {
|
if len(v) != 0 {
|
||||||
validSignatureSlice = append(validSignatureSlice, v)
|
validSignatures = append(validSignatures, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip and wait for the next vote to process again if valid votes is less than what we required
|
// Skip and wait for the next vote to process again if valid votes is less than what we required
|
||||||
if len(validSignatureSlice) < x.config.V2.CurrentConfig.CertThreshold {
|
certThreshold := x.config.V2.Config(uint64(currentVoteMsg.(*types.Vote).ProposedBlockInfo.Round)).CertThreshold
|
||||||
log.Warn("[onVotePoolThresholdReached] Not enough valid signatures to generate QC", "VotesSignaturesAfterFilter", validSignatureSlice, "NumberOfValidVotes", len(validSignatureSlice), "NumberOfVotes", len(pooledVotes))
|
if len(validSignatures) < certThreshold {
|
||||||
|
log.Warn("[onVotePoolThresholdReached] Not enough valid signatures to generate QC", "VotesSignaturesAfterFilter", validSignatures, "NumberOfValidVotes", len(validSignatures), "NumberOfVotes", len(pooledVotes))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Genrate QC
|
// Genrate QC
|
||||||
quorumCert := &types.QuorumCert{
|
quorumCert := &types.QuorumCert{
|
||||||
ProposedBlockInfo: currentVoteMsg.(*types.Vote).ProposedBlockInfo,
|
ProposedBlockInfo: currentVoteMsg.(*types.Vote).ProposedBlockInfo,
|
||||||
Signatures: validSignatureSlice,
|
Signatures: validSignatures,
|
||||||
GapNumber: currentVoteMsg.(*types.Vote).GapNumber,
|
GapNumber: currentVoteMsg.(*types.Vote).GapNumber,
|
||||||
}
|
}
|
||||||
err := x.processQC(chain, quorumCert)
|
err := x.processQC(chain, quorumCert)
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,9 @@ var (
|
||||||
|
|
||||||
ErrInvalidV2Extra = errors.New("Invalid v2 extra in the block")
|
ErrInvalidV2Extra = errors.New("Invalid v2 extra in the block")
|
||||||
ErrInvalidQC = errors.New("Invalid QC content")
|
ErrInvalidQC = errors.New("Invalid QC content")
|
||||||
|
ErrInvalidQCSignatures = errors.New("Invalid QC Signatures")
|
||||||
ErrInvalidTC = errors.New("Invalid TC content")
|
ErrInvalidTC = errors.New("Invalid TC content")
|
||||||
|
ErrInvalidTCSignatures = errors.New("Invalid TC Signatures")
|
||||||
ErrEmptyBlockInfoHash = errors.New("BlockInfo hash is empty")
|
ErrEmptyBlockInfoHash = errors.New("BlockInfo hash is empty")
|
||||||
ErrInvalidFieldInNonEpochSwitch = errors.New("Invalid field exist in a non-epoch swtich block")
|
ErrInvalidFieldInNonEpochSwitch = errors.New("Invalid field exist in a non-epoch swtich block")
|
||||||
ErrValidatorNotWithinMasternodes = errors.New("Validaotor address is not in the master node list")
|
ErrValidatorNotWithinMasternodes = errors.New("Validaotor address is not in the master node list")
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject the hardcoded master node list for the last v1 epoch block and all v1 epoch switch blocks (excluding genesis)
|
// Inject the hardcoded master node list for the last v1 epoch block and all v1 epoch switch blocks (excluding genesis)
|
||||||
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
||||||
// reset extra
|
// reset extra
|
||||||
header.Extra = []byte{}
|
header.Extra = []byte{}
|
||||||
if len(header.Extra) < utils.ExtraVanity {
|
if len(header.Extra) < utils.ExtraVanity {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ func TestAdaptorGetMasternodesFromCheckpointHeader(t *testing.T) {
|
||||||
headerV1.Extra = common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400")
|
headerV1.Extra = common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400")
|
||||||
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1)
|
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1)
|
||||||
headerV2 := currentBlock.Header()
|
headerV2 := currentBlock.Header()
|
||||||
headerV2.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(1))
|
headerV2.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(1))
|
||||||
headerV2.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c")
|
headerV2.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c")
|
||||||
headerV2.Extra = []byte{2}
|
headerV2.Extra = []byte{2}
|
||||||
masternodesV2 := adaptor.GetMasternodesFromCheckpointHeader(headerV2)
|
masternodesV2 := adaptor.GetMasternodesFromCheckpointHeader(headerV2)
|
||||||
|
|
@ -91,12 +91,12 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
parentBlockInfo := &types.BlockInfo{
|
parentBlockInfo := &types.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: types.Round(0),
|
Round: types.Round(0),
|
||||||
Number: big.NewInt(0).Set(blockchain.Config().XDPoS.V2.FirstSwitchBlock),
|
Number: big.NewInt(0).Set(blockchain.Config().XDPoS.V2.SwitchBlock),
|
||||||
}
|
}
|
||||||
quorumCert := &types.QuorumCert{
|
quorumCert := &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
||||||
}
|
}
|
||||||
extra := types.ExtraFields_v2{
|
extra := types.ExtraFields_v2{
|
||||||
Round: 1,
|
Round: 1,
|
||||||
|
|
@ -105,19 +105,19 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
extraBytes, err := extra.EncodeToBytes()
|
extraBytes, err := extra.EncodeToBytes()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(1))
|
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(1))
|
||||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||||
parentBlockInfo = &types.BlockInfo{
|
parentBlockInfo = &types.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: types.Round(1),
|
Round: types.Round(1),
|
||||||
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(1)),
|
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(1)),
|
||||||
}
|
}
|
||||||
quorumCert = &types.QuorumCert{
|
quorumCert = &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
||||||
}
|
}
|
||||||
extra = types.ExtraFields_v2{
|
extra = types.ExtraFields_v2{
|
||||||
Round: 2,
|
Round: 2,
|
||||||
|
|
@ -126,19 +126,19 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
extraBytes, err = extra.EncodeToBytes()
|
extraBytes, err = extra.EncodeToBytes()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(2))
|
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(2))
|
||||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||||
parentBlockInfo = &types.BlockInfo{
|
parentBlockInfo = &types.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: types.Round(blockchain.Config().XDPoS.Epoch) - 1,
|
Round: types.Round(blockchain.Config().XDPoS.Epoch) - 1,
|
||||||
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(100)),
|
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(100)),
|
||||||
}
|
}
|
||||||
quorumCert = &types.QuorumCert{
|
quorumCert = &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
||||||
}
|
}
|
||||||
extra = types.ExtraFields_v2{
|
extra = types.ExtraFields_v2{
|
||||||
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
||||||
|
|
@ -147,19 +147,19 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
extraBytes, err = extra.EncodeToBytes()
|
extraBytes, err = extra.EncodeToBytes()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(101))
|
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(101))
|
||||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||||
parentBlockInfo = &types.BlockInfo{
|
parentBlockInfo = &types.BlockInfo{
|
||||||
Hash: header.ParentHash,
|
Hash: header.ParentHash,
|
||||||
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
||||||
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(100)),
|
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(100)),
|
||||||
}
|
}
|
||||||
quorumCert = &types.QuorumCert{
|
quorumCert = &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
||||||
}
|
}
|
||||||
extra = types.ExtraFields_v2{
|
extra = types.ExtraFields_v2{
|
||||||
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 2,
|
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 2,
|
||||||
|
|
@ -168,7 +168,7 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
||||||
extraBytes, err = extra.EncodeToBytes()
|
extraBytes, err = extra.EncodeToBytes()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
header.Extra = extraBytes
|
header.Extra = extraBytes
|
||||||
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(101))
|
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(101))
|
||||||
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||||
|
|
|
||||||
|
|
@ -83,13 +83,13 @@ func TestIsYourTurnConsensusV2(t *testing.T) {
|
||||||
|
|
||||||
func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) {
|
func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) {
|
||||||
// we skip test for v1 since it's hard to make a real genesis block
|
// we skip test for v1 since it's hard to make a real genesis block
|
||||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, params.TestXDPoSMockChainConfig, nil)
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 909, params.TestXDPoSMockChainConfig, nil)
|
||||||
firstMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
|
firstMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
|
||||||
|
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
blockNum := 911 // 911 is new config switch block
|
blockNum := 910 // 910 is new config switch block
|
||||||
blockCoinBase := "0x111000000000000000000000000000000123"
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 1, blockCoinBase, signer, signFn, nil, nil)
|
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 10, blockCoinBase, signer, signFn, nil, nil)
|
||||||
currentBlockHeader := currentBlock.Header()
|
currentBlockHeader := currentBlock.Header()
|
||||||
currentBlockHeader.Time = big.NewInt(time.Now().Unix())
|
currentBlockHeader.Time = big.NewInt(time.Now().Unix())
|
||||||
err := blockchain.InsertBlock(currentBlock)
|
err := blockchain.InsertBlock(currentBlock)
|
||||||
|
|
@ -100,8 +100,11 @@ func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, isYourTurn)
|
assert.False(t, isYourTurn)
|
||||||
|
|
||||||
|
adaptor.UpdateParams(currentBlockHeader) // it will be triggered automatically on the real code by other process
|
||||||
|
|
||||||
// after new mine period
|
// after new mine period
|
||||||
secondMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
|
secondMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
|
||||||
|
|
||||||
time.Sleep(time.Duration(secondMinePeriod-firstMinePeriod) * time.Second)
|
time.Sleep(time.Duration(secondMinePeriod-firstMinePeriod) * time.Second)
|
||||||
isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -312,10 +312,10 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
||||||
for i := 1; i <= numOfBlocks; i++ {
|
for i := 1; i <= numOfBlocks; i++ {
|
||||||
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
||||||
// for v2 blocks, fill in correct coinbase
|
// for v2 blocks, fill in correct coinbase
|
||||||
if int64(i) > chainConfig.XDPoS.V2.FirstSwitchBlock.Int64() {
|
if int64(i) > chainConfig.XDPoS.V2.SwitchBlock.Int64() {
|
||||||
blockCoinBase = signer.Hex()
|
blockCoinBase = signer.Hex()
|
||||||
}
|
}
|
||||||
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()
|
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
|
||||||
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, nil, nil)
|
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, nil, nil)
|
||||||
|
|
||||||
err = blockchain.InsertBlock(block)
|
err = blockchain.InsertBlock(block)
|
||||||
|
|
@ -348,7 +348,7 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
||||||
}
|
}
|
||||||
|
|
||||||
// First v2 block
|
// First v2 block
|
||||||
if (int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()) == 1 {
|
if (int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()) == 1 {
|
||||||
lastv1BlockNumber := block.Header().Number.Uint64() - 1
|
lastv1BlockNumber := block.Header().Number.Uint64() - 1
|
||||||
checkpointBlockNumber := lastv1BlockNumber - lastv1BlockNumber%chainConfig.XDPoS.Epoch
|
checkpointBlockNumber := lastv1BlockNumber - lastv1BlockNumber%chainConfig.XDPoS.Epoch
|
||||||
checkpointHeader := blockchain.GetHeaderByNumber(checkpointBlockNumber)
|
checkpointHeader := blockchain.GetHeaderByNumber(checkpointBlockNumber)
|
||||||
|
|
@ -398,10 +398,10 @@ func PrepareXDCTestBlockChainWithPenaltyForV2Engine(t *testing.T, numOfBlocks in
|
||||||
for i := 1; i <= numOfBlocks; i++ {
|
for i := 1; i <= numOfBlocks; i++ {
|
||||||
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
||||||
// for v2 blocks, fill in correct coinbase
|
// for v2 blocks, fill in correct coinbase
|
||||||
if int64(i) > chainConfig.XDPoS.V2.FirstSwitchBlock.Int64() {
|
if int64(i) > chainConfig.XDPoS.V2.SwitchBlock.Int64() {
|
||||||
blockCoinBase = signer.Hex()
|
blockCoinBase = signer.Hex()
|
||||||
}
|
}
|
||||||
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()
|
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
|
||||||
// use signer itself as penalty
|
// use signer itself as penalty
|
||||||
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, signer[:], nil)
|
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, signer[:], nil)
|
||||||
|
|
||||||
|
|
@ -426,7 +426,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
||||||
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
|
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
|
||||||
var header *types.Header
|
var header *types.Header
|
||||||
|
|
||||||
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 1 { // Build engine v2 compatible extra data field
|
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 1 { // Build engine v2 compatible extra data field
|
||||||
extraInBytes := generateV2Extra(roundNumber, currentBlock, signer, signFn, signersKey)
|
extraInBytes := generateV2Extra(roundNumber, currentBlock, signer, signFn, signersKey)
|
||||||
|
|
||||||
header = &types.Header{
|
header = &types.Header{
|
||||||
|
|
@ -436,9 +436,9 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
||||||
Coinbase: common.HexToAddress(blockCoinBase),
|
Coinbase: common.HexToAddress(blockCoinBase),
|
||||||
Extra: extraInBytes,
|
Extra: extraInBytes,
|
||||||
}
|
}
|
||||||
if int64(blockNumber) == (chainConfig.XDPoS.V2.FirstSwitchBlock.Int64() + 1) { // This is the first v2 block, we need to copy the last v1 epoch master node list and inject into v2 validators
|
if int64(blockNumber) == (chainConfig.XDPoS.V2.SwitchBlock.Int64() + 1) { // This is the first v2 block, we need to copy the last v1 epoch master node list and inject into v2 validators
|
||||||
// Get last master node list from last v1 block
|
// Get last master node list from last v1 block
|
||||||
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.FirstSwitchBlock.Uint64())
|
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.SwitchBlock.Uint64())
|
||||||
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
|
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
|
||||||
for _, v := range masternodesFromV1LastEpoch {
|
for _, v := range masternodesFromV1LastEpoch {
|
||||||
header.Validators = append(header.Validators, v[:]...)
|
header.Validators = append(header.Validators, v[:]...)
|
||||||
|
|
@ -446,7 +446,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
||||||
} else if roundNumber%int64(chainConfig.XDPoS.Epoch) == 0 {
|
} else if roundNumber%int64(chainConfig.XDPoS.Epoch) == 0 {
|
||||||
// epoch switch blocks, copy the master node list and inject into v2 validators
|
// epoch switch blocks, copy the master node list and inject into v2 validators
|
||||||
// Get last master node list from last v1 block
|
// Get last master node list from last v1 block
|
||||||
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.FirstSwitchBlock.Uint64())
|
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.SwitchBlock.Uint64())
|
||||||
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
|
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
|
||||||
for _, v := range masternodesFromV1LastEpoch {
|
for _, v := range masternodesFromV1LastEpoch {
|
||||||
header.Validators = append(header.Validators, v[:]...)
|
header.Validators = append(header.Validators, v[:]...)
|
||||||
|
|
@ -465,7 +465,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject the hardcoded master node list for the last v1 epoch block and all v1 epoch switch blocks (excluding genesis)
|
// Inject the hardcoded master node list for the last v1 epoch block and all v1 epoch switch blocks (excluding genesis)
|
||||||
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
||||||
// reset extra
|
// reset extra
|
||||||
header.Extra = []byte{}
|
header.Extra = []byte{}
|
||||||
if len(header.Extra) < utils.ExtraVanity {
|
if len(header.Extra) < utils.ExtraVanity {
|
||||||
|
|
@ -584,7 +584,7 @@ func findSignerAndSignFn(bc *BlockChain, header *types.Header, signer common.Add
|
||||||
addressedSignFn := signFn
|
addressedSignFn := signFn
|
||||||
|
|
||||||
// If v2 block, we need to use extra data's round to find who is creating the block in order to verify the validator
|
// If v2 block, we need to use extra data's round to find who is creating the block in order to verify the validator
|
||||||
if header.Number.Cmp(config.XDPoS.V2.FirstSwitchBlock) > 0 {
|
if header.Number.Cmp(config.XDPoS.V2.SwitchBlock) > 0 {
|
||||||
var decodedExtraField types.ExtraFields_v2
|
var decodedExtraField types.ExtraFields_v2
|
||||||
err := utils.DecodeBytesExtraFields(header.Extra, &decodedExtraField)
|
err := utils.DecodeBytesExtraFields(header.Extra, &decodedExtraField)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitialFirstV2Blcok(t *testing.T) {
|
func TestInitialFirstV2Block(t *testing.T) {
|
||||||
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 900, params.TestXDPoSMockChainConfig, nil)
|
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 900, params.TestXDPoSMockChainConfig, nil)
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
header := currentBlock.Header()
|
header := currentBlock.Header()
|
||||||
|
|
@ -32,7 +32,7 @@ func TestInitialFirstV2Blcok(t *testing.T) {
|
||||||
expectedQuorumCert := &types.QuorumCert{
|
expectedQuorumCert := &types.QuorumCert{
|
||||||
ProposedBlockInfo: blockInfo,
|
ProposedBlockInfo: blockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
||||||
}
|
}
|
||||||
assert.Equal(t, types.Round(1), round)
|
assert.Equal(t, types.Round(1), round)
|
||||||
assert.Equal(t, expectedQuorumCert, highQC)
|
assert.Equal(t, expectedQuorumCert, highQC)
|
||||||
|
|
@ -104,7 +104,7 @@ func TestInitialOtherV2Block(t *testing.T) {
|
||||||
expectedQuorumCert := &types.QuorumCert{
|
expectedQuorumCert := &types.QuorumCert{
|
||||||
ProposedBlockInfo: blockInfo,
|
ProposedBlockInfo: blockInfo,
|
||||||
Signatures: []types.Signature{},
|
Signatures: []types.Signature{},
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
||||||
}
|
}
|
||||||
assert.Equal(t, types.Round(11), round)
|
assert.Equal(t, types.Round(11), round)
|
||||||
assert.Equal(t, expectedQuorumCert, highQC)
|
assert.Equal(t, expectedQuorumCert, highQC)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func TestHookRewardV2(t *testing.T) {
|
||||||
err = json.Unmarshal([]byte(configString), &config)
|
err = json.Unmarshal([]byte(configString), &config)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs
|
// set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs
|
||||||
config.XDPoS.V2.FirstSwitchBlock.SetUint64(1800)
|
config.XDPoS.V2.SwitchBlock.SetUint64(1800)
|
||||||
|
|
||||||
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*5, &config, nil)
|
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*5, &config, nil)
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ func TestHookRewardV2SplitReward(t *testing.T) {
|
||||||
err = json.Unmarshal([]byte(configString), &config)
|
err = json.Unmarshal([]byte(configString), &config)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs
|
// set switch to 1800, so that it covers 901-1799, 1800-2700 two epochs
|
||||||
config.XDPoS.V2.FirstSwitchBlock.SetUint64(1800)
|
config.XDPoS.V2.SwitchBlock.SetUint64(1800)
|
||||||
|
|
||||||
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*3, &config, nil)
|
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*3, &config, nil)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ func TestTimeoutPeriodAndThreadholdConfigChange(t *testing.T) {
|
||||||
err := blockchain.InsertBlock(currentBlock)
|
err := blockchain.InsertBlock(currentBlock)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
engineV2.UpdateParams() // it will be triggered automatically on the real code by other process
|
engineV2.UpdateParams(currentBlockHeader) // it will be triggered automatically on the real code by other process
|
||||||
|
|
||||||
t.Log("waiting for another consecutive period")
|
t.Log("waiting for another consecutive period")
|
||||||
// another consecutive period
|
// another consecutive period
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
|
||||||
|
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
||||||
// Genrate QC
|
// Genrate 911 QC
|
||||||
proposedBlockInfo := &types.BlockInfo{
|
proposedBlockInfo := &types.BlockInfo{
|
||||||
Hash: blockchain.GetBlockByNumber(911).Hash(),
|
Hash: blockchain.GetBlockByNumber(911).Hash(),
|
||||||
Round: types.Round(11),
|
Round: types.Round(11),
|
||||||
|
|
@ -198,11 +198,11 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
|
||||||
acc1SignedHash := SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
acc1SignedHash := SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
||||||
acc2SignedHash := SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
acc2SignedHash := SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
||||||
acc3SignedHash := SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
acc3SignedHash := SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
||||||
var signatures []types.Signature
|
var signaturesFirst []types.Signature
|
||||||
signatures = append(signatures, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
signaturesFirst = append(signaturesFirst, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
||||||
quorumCert := &types.QuorumCert{
|
quorumCert := &types.QuorumCert{
|
||||||
ProposedBlockInfo: proposedBlockInfo,
|
ProposedBlockInfo: proposedBlockInfo,
|
||||||
Signatures: signatures,
|
Signatures: signaturesFirst,
|
||||||
GapNumber: 450,
|
GapNumber: 450,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,18 +210,53 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
|
||||||
Round: types.Round(12),
|
Round: types.Round(12),
|
||||||
QuorumCert: quorumCert,
|
QuorumCert: quorumCert,
|
||||||
}
|
}
|
||||||
extraInBytes, err := extra.EncodeToBytes()
|
extraInBytes, _ := extra.EncodeToBytes()
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// after 910 require 5 signs, but we only give 3 signs
|
// after 910 require 5 signs, but we only give 3 signs
|
||||||
block912 := blockchain.GetBlockByNumber(912).Header()
|
block912 := blockchain.GetBlockByNumber(912).Header()
|
||||||
block912.Extra = extraInBytes
|
block912.Extra = extraInBytes
|
||||||
err = adaptor.VerifyHeader(blockchain, block912, true)
|
err = adaptor.VerifyHeader(blockchain, block912, true)
|
||||||
|
|
||||||
// Error happens after verify QC, means verify QC passed
|
assert.Equal(t, utils.ErrInvalidQCSignatures, err)
|
||||||
assert.Equal(t, utils.ErrInvalidQC, err)
|
|
||||||
|
// Make we verification process use the corresponding config
|
||||||
|
// Genrate 910 QC
|
||||||
|
proposedBlockInfo = &types.BlockInfo{
|
||||||
|
Hash: blockchain.GetBlockByNumber(910).Hash(),
|
||||||
|
Round: types.Round(10),
|
||||||
|
Number: blockchain.GetBlockByNumber(910).Number(),
|
||||||
|
}
|
||||||
|
voteForSign = &types.VoteForSign{
|
||||||
|
ProposedBlockInfo: proposedBlockInfo,
|
||||||
|
GapNumber: 450,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign from acc 1, 2, 3
|
||||||
|
acc1SignedHash = SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
||||||
|
acc2SignedHash = SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
||||||
|
acc3SignedHash = SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
||||||
|
|
||||||
|
var signaturesThr []types.Signature
|
||||||
|
signaturesThr = append(signaturesThr, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
||||||
|
quorumCert = &types.QuorumCert{
|
||||||
|
ProposedBlockInfo: proposedBlockInfo,
|
||||||
|
Signatures: signaturesThr,
|
||||||
|
GapNumber: 450,
|
||||||
|
}
|
||||||
|
|
||||||
|
extra = types.ExtraFields_v2{
|
||||||
|
Round: types.Round(11),
|
||||||
|
QuorumCert: quorumCert,
|
||||||
|
}
|
||||||
|
extraInBytes, _ = extra.EncodeToBytes()
|
||||||
|
|
||||||
|
// QC contains 910, so it requires 3 signatures, not use block number to determine which config to use
|
||||||
|
block911 := blockchain.GetBlockByNumber(911).Header()
|
||||||
|
block911.Extra = extraInBytes
|
||||||
|
err = adaptor.VerifyHeader(blockchain, block911, true)
|
||||||
|
|
||||||
|
// error ErrValidatorNotWithinMasternodes means verifyQC is passed and move to next verification process
|
||||||
|
assert.Equal(t, utils.ErrValidatorNotWithinMasternodes, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
||||||
|
|
@ -271,7 +306,7 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
||||||
headerWithDuplicatedSignatures.Extra = extraInBytes
|
headerWithDuplicatedSignatures.Extra = extraInBytes
|
||||||
// Happy path
|
// Happy path
|
||||||
err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true)
|
err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true)
|
||||||
assert.Equal(t, utils.ErrInvalidQC, err)
|
assert.Equal(t, utils.ErrInvalidQCSignatures, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,12 +367,12 @@ func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
|
||||||
|
|
||||||
// Create block 911 but don't write into DB
|
// Create block 911 but don't write into DB
|
||||||
blockNumber := 911
|
blockNumber := 911
|
||||||
roundNumber := int64(blockNumber) - config.XDPoS.V2.FirstSwitchBlock.Int64()
|
roundNumber := int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
|
||||||
block911 := CreateBlock(blockchain, &config, block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil)
|
block911 := CreateBlock(blockchain, &config, block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil)
|
||||||
|
|
||||||
// Create block 912 and not write into DB as well
|
// Create block 912 and not write into DB as well
|
||||||
blockNumber = 912
|
blockNumber = 912
|
||||||
roundNumber = int64(blockNumber) - config.XDPoS.V2.FirstSwitchBlock.Int64()
|
roundNumber = int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
|
||||||
block912 := CreateBlock(blockchain, &config, block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil)
|
block912 := CreateBlock(blockchain, &config, block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil)
|
||||||
|
|
||||||
headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header())
|
headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header())
|
||||||
|
|
|
||||||
|
|
@ -2541,7 +2541,7 @@ func (bc *BlockChain) UpdateM1() error {
|
||||||
header := bc.CurrentHeader()
|
header := bc.CurrentHeader()
|
||||||
var maxMasternodes int
|
var maxMasternodes int
|
||||||
// check if block number is increase ms checkpoint
|
// check if block number is increase ms checkpoint
|
||||||
if bc.chainConfig.IsTIPIncreaseMasternodes(header.Number) || (bc.chainConfig.XDPoS.V2.FirstSwitchBlock != nil && header.Number.Cmp(bc.chainConfig.XDPoS.V2.FirstSwitchBlock) == 1) {
|
if bc.chainConfig.IsTIPIncreaseMasternodes(header.Number) || (bc.chainConfig.XDPoS.V2.SwitchBlock != nil && header.Number.Cmp(bc.chainConfig.XDPoS.V2.SwitchBlock) == 1) {
|
||||||
// using new masterndoes
|
// using new masterndoes
|
||||||
maxMasternodes = common.MaxMasternodesV2
|
maxMasternodes = common.MaxMasternodesV2
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,6 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
|
||||||
// DefaultGenesisBlock returns the Ethereum main net genesis block.
|
// DefaultGenesisBlock returns the Ethereum main net genesis block.
|
||||||
func DefaultGenesisBlock() *Genesis {
|
func DefaultGenesisBlock() *Genesis {
|
||||||
config := params.XDCMainnetChainConfig
|
config := params.XDCMainnetChainConfig
|
||||||
config.XDPoS.V2 = nil
|
|
||||||
return &Genesis{
|
return &Genesis{
|
||||||
Config: config,
|
Config: config,
|
||||||
Nonce: 0,
|
Nonce: 0,
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
|
|
||||||
// get list check penalties signing block & list master nodes wil comeback
|
// get list check penalties signing block & list master nodes wil comeback
|
||||||
// start to calc comeback at v2 block + limitPenaltyEpochV2 to avoid reading v1 blocks
|
// start to calc comeback at v2 block + limitPenaltyEpochV2 to avoid reading v1 blocks
|
||||||
comebackHeight := (common.LimitPenaltyEpochV2+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.FirstSwitchBlock.Uint64()
|
comebackHeight := (common.LimitPenaltyEpochV2+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.SwitchBlock.Uint64()
|
||||||
penComebacks := []common.Address{}
|
penComebacks := []common.Address{}
|
||||||
if number.Uint64() > comebackHeight {
|
if number.Uint64() > comebackHeight {
|
||||||
pens := adaptor.EngineV2.GetPreviousPenaltyByHash(chain, currentHash, common.LimitPenaltyEpochV2)
|
pens := adaptor.EngineV2.GetPreviousPenaltyByHash(chain, currentHash, common.LimitPenaltyEpochV2)
|
||||||
|
|
@ -170,7 +170,7 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
}
|
}
|
||||||
rewards := make(map[string]interface{})
|
rewards := make(map[string]interface{})
|
||||||
// skip hook reward if this is the first v2
|
// skip hook reward if this is the first v2
|
||||||
if number == chain.Config().XDPoS.V2.FirstSwitchBlock.Uint64()+1 {
|
if number == chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
|
||||||
return rewards, nil
|
return rewards, nil
|
||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
@ -235,7 +235,7 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if isEpochSwitch && i != chain.Config().XDPoS.V2.FirstSwitchBlock.Uint64()+1 {
|
if isEpochSwitch && i != chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
|
||||||
epochCount += 1
|
epochCount += 1
|
||||||
if epochCount == signEpochCount {
|
if epochCount == signEpochCount {
|
||||||
endBlockNumber = header.Number.Uint64() - 1
|
endBlockNumber = header.Number.Uint64() - 1
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ func (self *worker) update() {
|
||||||
// A real event arrived, process interesting content
|
// A real event arrived, process interesting content
|
||||||
select {
|
select {
|
||||||
case v := <-WaitPeriodCh:
|
case v := <-WaitPeriodCh:
|
||||||
log.Info("[worker] update mine period", "period", v)
|
log.Info("[worker] update wait period", "period", v)
|
||||||
waitPeriod = v
|
waitPeriod = v
|
||||||
timeout.Reset(time.Duration(waitPeriod) * time.Second)
|
timeout.Reset(time.Duration(waitPeriod) * time.Second)
|
||||||
|
|
||||||
|
|
|
||||||
183
params/config.go
183
params/config.go
|
|
@ -19,8 +19,10 @@ package params
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -39,7 +41,7 @@ var (
|
||||||
var (
|
var (
|
||||||
MainnetV2Configs = map[uint64]*V2Config{
|
MainnetV2Configs = map[uint64]*V2Config{
|
||||||
Default: {
|
Default: {
|
||||||
SwitchBlock: big.NewInt(9999999999),
|
SwitchRound: 0,
|
||||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
TimeoutSyncThreshold: 3,
|
TimeoutSyncThreshold: 3,
|
||||||
TimeoutPeriod: 60,
|
TimeoutPeriod: 60,
|
||||||
|
|
@ -47,7 +49,7 @@ var (
|
||||||
MinePeriod: 10,
|
MinePeriod: 10,
|
||||||
},
|
},
|
||||||
9999999999: {
|
9999999999: {
|
||||||
SwitchBlock: big.NewInt(9999999999),
|
SwitchRound: 9999999999,
|
||||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
TimeoutSyncThreshold: 3,
|
TimeoutSyncThreshold: 3,
|
||||||
TimeoutPeriod: 60,
|
TimeoutPeriod: 60,
|
||||||
|
|
@ -57,31 +59,23 @@ var (
|
||||||
}
|
}
|
||||||
TestV2Configs = map[uint64]*V2Config{
|
TestV2Configs = map[uint64]*V2Config{
|
||||||
Default: {
|
Default: {
|
||||||
SwitchBlock: big.NewInt(900),
|
SwitchRound: 0,
|
||||||
CertThreshold: 3,
|
CertThreshold: 3,
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 4,
|
TimeoutPeriod: 4,
|
||||||
WaitPeriod: 1,
|
WaitPeriod: 1,
|
||||||
MinePeriod: 2,
|
MinePeriod: 2,
|
||||||
},
|
},
|
||||||
900: {
|
10: {
|
||||||
SwitchBlock: big.NewInt(900),
|
SwitchRound: 10,
|
||||||
CertThreshold: 3,
|
|
||||||
TimeoutSyncThreshold: 2,
|
|
||||||
TimeoutPeriod: 4,
|
|
||||||
WaitPeriod: 1,
|
|
||||||
MinePeriod: 2,
|
|
||||||
},
|
|
||||||
910: {
|
|
||||||
SwitchBlock: big.NewInt(910),
|
|
||||||
CertThreshold: 5,
|
CertThreshold: 5,
|
||||||
TimeoutSyncThreshold: 2,
|
TimeoutSyncThreshold: 2,
|
||||||
TimeoutPeriod: 4,
|
TimeoutPeriod: 4,
|
||||||
WaitPeriod: 2,
|
WaitPeriod: 2,
|
||||||
MinePeriod: 3,
|
MinePeriod: 3,
|
||||||
},
|
},
|
||||||
1799: {
|
899: {
|
||||||
SwitchBlock: big.NewInt(1799),
|
SwitchRound: 899,
|
||||||
CertThreshold: 5,
|
CertThreshold: 5,
|
||||||
TimeoutSyncThreshold: 4,
|
TimeoutSyncThreshold: 4,
|
||||||
TimeoutPeriod: 5,
|
TimeoutPeriod: 5,
|
||||||
|
|
@ -92,31 +86,23 @@ var (
|
||||||
|
|
||||||
DevnetV2Configs = map[uint64]*V2Config{
|
DevnetV2Configs = map[uint64]*V2Config{
|
||||||
Default: {
|
Default: {
|
||||||
SwitchBlock: big.NewInt(7074000),
|
SwitchRound: 0,
|
||||||
CertThreshold: 4,
|
|
||||||
TimeoutSyncThreshold: 5,
|
|
||||||
TimeoutPeriod: 10,
|
|
||||||
WaitPeriod: 5,
|
|
||||||
MinePeriod: 5,
|
|
||||||
},
|
|
||||||
7074000: {
|
|
||||||
SwitchBlock: big.NewInt(7074000),
|
|
||||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
TimeoutSyncThreshold: 5,
|
TimeoutSyncThreshold: 5,
|
||||||
TimeoutPeriod: 25,
|
TimeoutPeriod: 25,
|
||||||
WaitPeriod: 10,
|
WaitPeriod: 10,
|
||||||
MinePeriod: 10,
|
MinePeriod: 10,
|
||||||
},
|
},
|
||||||
7224300: {
|
151919: {
|
||||||
SwitchBlock: big.NewInt(7224300),
|
SwitchRound: 151919,
|
||||||
CertThreshold: common.MaxMasternodesV2*1/2 + 1,
|
CertThreshold: common.MaxMasternodesV2*1/2 + 1,
|
||||||
TimeoutSyncThreshold: 8,
|
TimeoutSyncThreshold: 8,
|
||||||
TimeoutPeriod: 50,
|
TimeoutPeriod: 50,
|
||||||
WaitPeriod: 5,
|
WaitPeriod: 5,
|
||||||
MinePeriod: 20,
|
MinePeriod: 20,
|
||||||
},
|
},
|
||||||
7242300: {
|
171000: {
|
||||||
SwitchBlock: big.NewInt(7242300),
|
SwitchRound: 171000,
|
||||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
TimeoutSyncThreshold: 5,
|
TimeoutSyncThreshold: 5,
|
||||||
TimeoutPeriod: 25,
|
TimeoutPeriod: 25,
|
||||||
|
|
@ -142,9 +128,9 @@ var (
|
||||||
Gap: 450,
|
Gap: 450,
|
||||||
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
|
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
|
||||||
V2: &V2{
|
V2: &V2{
|
||||||
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
|
SwitchBlock: big.NewInt(9999999999),
|
||||||
CurrentConfig: MainnetV2Configs[0],
|
CurrentConfig: MainnetV2Configs[0],
|
||||||
AllConfigs: MainnetV2Configs,
|
AllConfigs: MainnetV2Configs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +170,7 @@ var (
|
||||||
Gap: 450,
|
Gap: 450,
|
||||||
FoudationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"),
|
FoudationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"),
|
||||||
V2: &V2{
|
V2: &V2{
|
||||||
FirstSwitchBlock: TestV2Configs[0].SwitchBlock,
|
SwitchBlock: big.NewInt(900),
|
||||||
CurrentConfig: TestV2Configs[0],
|
CurrentConfig: TestV2Configs[0],
|
||||||
AllConfigs: TestV2Configs,
|
AllConfigs: TestV2Configs,
|
||||||
SkipV2Validation: true,
|
SkipV2Validation: true,
|
||||||
|
|
@ -209,9 +195,9 @@ var (
|
||||||
Gap: 450,
|
Gap: 450,
|
||||||
FoudationWalletAddr: common.HexToAddress("0x746249c61f5832c5eed53172776b460491bdcd5c"),
|
FoudationWalletAddr: common.HexToAddress("0x746249c61f5832c5eed53172776b460491bdcd5c"),
|
||||||
V2: &V2{
|
V2: &V2{
|
||||||
FirstSwitchBlock: DevnetV2Configs[0].SwitchBlock,
|
SwitchBlock: big.NewInt(7074000),
|
||||||
CurrentConfig: DevnetV2Configs[0],
|
CurrentConfig: DevnetV2Configs[0],
|
||||||
AllConfigs: DevnetV2Configs,
|
AllConfigs: DevnetV2Configs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -232,9 +218,9 @@ var (
|
||||||
Period: 15,
|
Period: 15,
|
||||||
Epoch: 30000,
|
Epoch: 30000,
|
||||||
V2: &V2{
|
V2: &V2{
|
||||||
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
|
SwitchBlock: big.NewInt(9999999999),
|
||||||
CurrentConfig: MainnetV2Configs[0],
|
CurrentConfig: MainnetV2Configs[0],
|
||||||
AllConfigs: MainnetV2Configs,
|
AllConfigs: MainnetV2Configs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -275,9 +261,9 @@ var (
|
||||||
FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
|
FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
|
||||||
Reward: 250,
|
Reward: 250,
|
||||||
V2: &V2{
|
V2: &V2{
|
||||||
FirstSwitchBlock: TestV2Configs[0].SwitchBlock,
|
SwitchBlock: big.NewInt(900),
|
||||||
CurrentConfig: TestV2Configs[0],
|
CurrentConfig: TestV2Configs[0],
|
||||||
AllConfigs: TestV2Configs,
|
AllConfigs: TestV2Configs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -347,27 +333,78 @@ type XDPoSConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2 struct {
|
type V2 struct {
|
||||||
FirstSwitchBlock *big.Int `json:"switchBlock"`
|
lock sync.RWMutex // Protects the signer fields
|
||||||
CurrentConfig *V2Config `json:"config"`
|
|
||||||
AllConfigs map[uint64]*V2Config `json:"allConfigs"`
|
SwitchBlock *big.Int `json:"switchBlock"`
|
||||||
configIndex []uint64 //list of switch block of configs
|
CurrentConfig *V2Config `json:"config"`
|
||||||
SkipV2Validation bool //Skip Block Validation for testing purpose, V2 consensus only
|
AllConfigs map[uint64]*V2Config `json:"allConfigs"`
|
||||||
|
configIndex []uint64 //list of switch block of configs
|
||||||
|
|
||||||
|
SkipV2Validation bool //Skip Block Validation for testing purpose, V2 consensus only
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2Config struct {
|
type V2Config struct {
|
||||||
WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event
|
SwitchRound uint64 `json:"switchRound"` // v1 to v2 switch block number
|
||||||
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
|
WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event
|
||||||
SwitchBlock *big.Int `json:"switchBlock"` // v1 to v2 switch block number
|
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
|
||||||
TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
|
TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
|
||||||
TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
|
TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
|
||||||
CertThreshold int `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate
|
CertThreshold int `json:"certificateThreshold"` // Necessary number of messages from master nodes to form a certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the stringer interface, returning the consensus engine details.
|
func (c *XDPoSConfig) String() string {
|
||||||
func (c *XDPoSConfig) BuildConfigIndex() {
|
return "XDPoS"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *XDPoSConfig) BlockConsensusVersion(num *big.Int, extraByte []byte, extraCheck bool) string {
|
||||||
|
if extraCheck && (len(extraByte) == 0 || extraByte[0] != 2) {
|
||||||
|
return ConsensusEngineVersion1
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.V2 != nil && c.V2.SwitchBlock != nil && num.Cmp(c.V2.SwitchBlock) > 0 {
|
||||||
|
return ConsensusEngineVersion2
|
||||||
|
}
|
||||||
|
return ConsensusEngineVersion1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *V2) UpdateConfig(round uint64) {
|
||||||
|
v.lock.Lock()
|
||||||
|
defer v.lock.Unlock()
|
||||||
|
|
||||||
|
var index uint64
|
||||||
|
|
||||||
|
//find the right config
|
||||||
|
for i := range v.configIndex {
|
||||||
|
if v.configIndex[i] <= round {
|
||||||
|
index = v.configIndex[i]
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update to current config
|
||||||
|
log.Info("[updateV2Config] Update config", "index", index, "round", round, "SwitchRound", v.AllConfigs[index].SwitchRound)
|
||||||
|
v.CurrentConfig = v.AllConfigs[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *V2) Config(round uint64) *V2Config {
|
||||||
|
configRound := round - 1 //start from next block from SwitchRound number
|
||||||
|
var index uint64
|
||||||
|
|
||||||
|
//find the right config
|
||||||
|
for i := range v.configIndex {
|
||||||
|
if v.configIndex[i] <= configRound {
|
||||||
|
index = v.configIndex[i]
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v.AllConfigs[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *V2) BuildConfigIndex() {
|
||||||
var list []uint64
|
var list []uint64
|
||||||
|
|
||||||
for i := range c.V2.AllConfigs {
|
for i := range v.AllConfigs {
|
||||||
list = append(list, i)
|
list = append(list, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,40 +416,12 @@ func (c *XDPoSConfig) BuildConfigIndex() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.V2.configIndex = list
|
log.Info("[BuildConfigIndex] config list", "list", list)
|
||||||
|
v.configIndex = list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *XDPoSConfig) String() string {
|
func (v *V2) ConfigIndex() []uint64 {
|
||||||
return "XDPoS"
|
return v.configIndex
|
||||||
}
|
|
||||||
|
|
||||||
func (c *XDPoSConfig) updateV2Config(num uint64) {
|
|
||||||
var index uint64
|
|
||||||
|
|
||||||
//find the right config
|
|
||||||
for i := range c.V2.configIndex {
|
|
||||||
if c.V2.configIndex[i] <= num {
|
|
||||||
index = c.V2.configIndex[i]
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// update to current config
|
|
||||||
c.V2.CurrentConfig = c.V2.AllConfigs[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *XDPoSConfig) BlockConsensusVersion(num *big.Int, extraByte []byte, skipExtraCheck bool) string {
|
|
||||||
if !skipExtraCheck && (len(extraByte) == 0 || extraByte[0] != 2) {
|
|
||||||
return ConsensusEngineVersion1
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.V2 != nil && c.V2.FirstSwitchBlock != nil && num.Cmp(c.V2.FirstSwitchBlock) > 0 {
|
|
||||||
// We have to check each block configuration due to reorg chain case
|
|
||||||
// Block may get rollback and old config need to apply to verify block
|
|
||||||
c.updateV2Config(num.Uint64() - 1)
|
|
||||||
return ConsensusEngineVersion2
|
|
||||||
}
|
|
||||||
return ConsensusEngineVersion1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the fmt.Stringer interface.
|
// String implements the fmt.Stringer interface.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCheckCompatible(t *testing.T) {
|
func TestCheckCompatible(t *testing.T) {
|
||||||
|
|
@ -79,3 +81,39 @@ func TestCheckCompatible(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateV2Config(t *testing.T) {
|
||||||
|
TestnetChainConfig.XDPoS.V2.BuildConfigIndex()
|
||||||
|
c := TestnetChainConfig.XDPoS.V2.CurrentConfig
|
||||||
|
assert.Equal(t, 3, c.CertThreshold)
|
||||||
|
|
||||||
|
TestnetChainConfig.XDPoS.V2.UpdateConfig(10)
|
||||||
|
c = TestnetChainConfig.XDPoS.V2.CurrentConfig
|
||||||
|
assert.Equal(t, 5, c.CertThreshold)
|
||||||
|
|
||||||
|
TestnetChainConfig.XDPoS.V2.UpdateConfig(899)
|
||||||
|
c = TestnetChainConfig.XDPoS.V2.CurrentConfig
|
||||||
|
assert.Equal(t, 4, c.TimeoutSyncThreshold)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestV2Config(t *testing.T) {
|
||||||
|
TestnetChainConfig.XDPoS.V2.BuildConfigIndex()
|
||||||
|
c := TestnetChainConfig.XDPoS.V2.Config(1)
|
||||||
|
assert.Equal(t, 3, c.CertThreshold)
|
||||||
|
|
||||||
|
c = TestnetChainConfig.XDPoS.V2.Config(5)
|
||||||
|
assert.Equal(t, 3, c.CertThreshold)
|
||||||
|
|
||||||
|
c = TestnetChainConfig.XDPoS.V2.Config(10)
|
||||||
|
assert.Equal(t, 3, c.CertThreshold)
|
||||||
|
|
||||||
|
c = TestnetChainConfig.XDPoS.V2.Config(11)
|
||||||
|
assert.Equal(t, 5, c.CertThreshold)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuildConfigIndex(t *testing.T) {
|
||||||
|
TestnetChainConfig.XDPoS.V2.BuildConfigIndex()
|
||||||
|
index := TestnetChainConfig.XDPoS.V2.ConfigIndex()
|
||||||
|
expected := []uint64{0, 10, 899}
|
||||||
|
assert.Equal(t, expected, index)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue