mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
Xin 259 support multi v2 config (#210)
* update timeout period and waittime * remove wrong comment * update config for preparing test
This commit is contained in:
parent
ff6ee67462
commit
6ffbd3e141
26 changed files with 469 additions and 171 deletions
|
|
@ -301,7 +301,7 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
|
||||||
if err := stack.Service(ðereum); err != nil {
|
if err := stack.Service(ðereum); err != nil {
|
||||||
utils.Fatalf("Ethereum service not running: %v", err)
|
utils.Fatalf("Ethereum service not running: %v", err)
|
||||||
}
|
}
|
||||||
if _, ok := ethereum.Engine().(*XDPoS.XDPoS); ok {
|
if engine, ok := ethereum.Engine().(*XDPoS.XDPoS); ok {
|
||||||
go func() {
|
go func() {
|
||||||
started := false
|
started := false
|
||||||
ok := false
|
ok := false
|
||||||
|
|
@ -345,6 +345,8 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
|
||||||
defer close(core.CheckpointCh)
|
defer close(core.CheckpointCh)
|
||||||
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")
|
||||||
|
engine.UpdateParams()
|
||||||
if common.IsTestnet {
|
if common.IsTestnet {
|
||||||
ok, err = ethereum.ValidateMasternodeTestnet()
|
ok, err = ethereum.ValidateMasternodeTestnet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ func (t *CountdownTimer) StopTimer() {
|
||||||
<-q
|
<-q
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *CountdownTimer) SetTimeoutDuration(duration time.Duration) {
|
||||||
|
t.timeoutDuration = duration
|
||||||
|
}
|
||||||
|
|
||||||
// Reset will start the countdown timer if it's already stopped, or simply reset the countdown time back to the defual `duration`
|
// Reset will start the countdown timer if it's already stopped, or simply reset the countdown time back to the defual `duration`
|
||||||
func (t *CountdownTimer) Reset(i interface{}) {
|
func (t *CountdownTimer) Reset(i interface{}) {
|
||||||
if !t.isInitilised() {
|
if !t.isInitilised() {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,11 @@ 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 = params.XDPoSV2Config
|
config.V2 = ¶ms.V2{
|
||||||
|
FirstSwitchBlock: params.MainnetV2Configs[0].SwitchBlock,
|
||||||
|
CurrentConfig: params.MainnetV2Configs[0],
|
||||||
|
AllConfigs: params.MainnetV2Configs,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("xdc config loading", "config", config)
|
log.Info("xdc config loading", "config", config)
|
||||||
|
|
@ -140,6 +144,11 @@ func NewFaker(db ethdb.Database, chainConfig *params.ChainConfig) *XDPoS {
|
||||||
return fakeEngine
|
return fakeEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset parameters after checkpoint due to config may change
|
||||||
|
func (x *XDPoS) UpdateParams() {
|
||||||
|
x.EngineV2.UpdateParams()
|
||||||
|
}
|
||||||
|
|
||||||
func (x *XDPoS) Initial(chain consensus.ChainReader, header *types.Header) error {
|
func (x *XDPoS) Initial(chain consensus.ChainReader, header *types.Header) error {
|
||||||
switch x.config.BlockConsensusVersion(header.Number, header.Extra, ExtraFieldCheck) {
|
switch x.config.BlockConsensusVersion(header.Number, header.Extra, ExtraFieldCheck) {
|
||||||
case params.ConsensusEngineVersion2:
|
case params.ConsensusEngineVersion2:
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ type XDPoS_v2 struct {
|
||||||
|
|
||||||
func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 {
|
func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 {
|
||||||
// Setup timeoutTimer
|
// Setup timeoutTimer
|
||||||
duration := time.Duration(config.V2.TimeoutPeriod) * time.Second
|
duration := time.Duration(config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
||||||
timeoutTimer := countdown.NewCountDown(duration)
|
timeoutTimer := countdown.NewCountDown(duration)
|
||||||
|
|
||||||
snapshots, _ := lru.NewARC(utils.InmemorySnapshots)
|
snapshots, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||||
|
|
@ -74,8 +74,8 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *
|
||||||
epochSwitches, _ := lru.NewARC(int(utils.InmemoryEpochs))
|
epochSwitches, _ := lru.NewARC(int(utils.InmemoryEpochs))
|
||||||
verifiedHeaders, _ := lru.NewARC(utils.InmemorySnapshots)
|
verifiedHeaders, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||||
|
|
||||||
timeoutPool := utils.NewPool(config.V2.CertThreshold)
|
timeoutPool := utils.NewPool()
|
||||||
votePool := utils.NewPool(config.V2.CertThreshold)
|
votePool := utils.NewPool()
|
||||||
engine := &XDPoS_v2{
|
engine := &XDPoS_v2{
|
||||||
config: config,
|
config: config,
|
||||||
db: db,
|
db: db,
|
||||||
|
|
@ -116,6 +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()
|
||||||
|
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
@ -129,6 +130,18 @@ 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
|
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() {
|
||||||
|
// Setup timeoutTimer
|
||||||
|
duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
||||||
|
x.timeoutWorker.SetTimeoutDuration(duration)
|
||||||
|
|
||||||
|
// avoid deadlock
|
||||||
|
go func() {
|
||||||
|
x.waitPeriodCh <- x.config.V2.CurrentConfig.WaitPeriod
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) SignHash(header *types.Header) (hash common.Hash) {
|
func (x *XDPoS_v2) SignHash(header *types.Header) (hash common.Hash) {
|
||||||
return sigHash(header)
|
return sigHash(header)
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +163,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.SwitchBlock.Int64() {
|
if header.Number.Int64() == x.config.V2.FirstSwitchBlock.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(),
|
||||||
|
|
@ -180,13 +193,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.SwitchBlock.Uint64() - x.config.Gap
|
lastGapNum := x.config.V2.FirstSwitchBlock.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.SwitchBlock.Uint64())
|
checkpointHeader := chain.GetHeaderByNumber(x.config.V2.FirstSwitchBlock.Uint64())
|
||||||
|
|
||||||
log.Info("[initial] init first snapshot")
|
log.Info("[initial] init first snapshot")
|
||||||
_, _, masternodes, err := x.getExtraFields(checkpointHeader)
|
_, _, masternodes, err := x.getExtraFields(checkpointHeader)
|
||||||
|
|
@ -204,10 +217,10 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial timeout
|
// Initial timeout
|
||||||
log.Info("[initial] miner wait period", "period", x.config.V2.WaitPeriod)
|
log.Info("[initial] miner wait period", "period", x.config.V2.CurrentConfig.WaitPeriod)
|
||||||
// avoid deadlock
|
// avoid deadlock
|
||||||
go func() {
|
go func() {
|
||||||
x.waitPeriodCh <- x.config.V2.WaitPeriod
|
x.waitPeriodCh <- x.config.V2.CurrentConfig.WaitPeriod
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Kick-off the countdown timer
|
// Kick-off the countdown timer
|
||||||
|
|
@ -233,8 +246,8 @@ 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.MinePeriod) {
|
if waitedTime < int64(x.config.V2.CurrentConfig.MinePeriod) {
|
||||||
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.MinePeriod, "waitedTime", waitedTime)
|
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.CurrentConfig.MinePeriod, "waitedTime", waitedTime)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -705,7 +718,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.SwitchBlock) == 0 {
|
if blockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 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")
|
||||||
|
|
@ -753,7 +766,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
if quorumCert == nil {
|
if quorumCert == nil {
|
||||||
log.Warn("[verifyQC] QC is Nil")
|
log.Warn("[verifyQC] QC is Nil")
|
||||||
return utils.ErrInvalidQC
|
return utils.ErrInvalidQC
|
||||||
} else if (quorumCert.ProposedBlockInfo.Number.Uint64() > x.config.V2.SwitchBlock.Uint64()) && (signatures == nil || (len(signatures) < x.config.V2.CertThreshold)) {
|
} else if (quorumCert.ProposedBlockInfo.Number.Uint64() > x.config.V2.FirstSwitchBlock.Uint64()) && (signatures == nil || (len(signatures) < x.config.V2.CurrentConfig.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 empty", "QC", quorumCert, "QCNumber", quorumCert.ProposedBlockInfo.Number, "Signatures len", len(signatures))
|
||||||
return utils.ErrInvalidQC
|
return utils.ErrInvalidQC
|
||||||
|
|
@ -813,7 +826,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.SwitchBlock) > 0 {
|
if proposedBlockHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) > 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 {
|
||||||
|
|
@ -869,7 +882,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.SwitchBlock) <= 0 {
|
if big.NewInt(0).Sub(proposedBlockHeader.Number, big.NewInt(2)).Cmp(x.config.V2.FirstSwitchBlock) <= 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
|
||||||
|
|
@ -946,7 +959,7 @@ func (x *XDPoS_v2) calcMasternodes(chain consensus.ChainReader, blockNum *big.In
|
||||||
}
|
}
|
||||||
candidates := snap.NextEpochMasterNodes
|
candidates := snap.NextEpochMasterNodes
|
||||||
|
|
||||||
if blockNum.Uint64() == x.config.V2.SwitchBlock.Uint64()+1 {
|
if blockNum.Uint64() == x.config.V2.FirstSwitchBlock.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.SwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
|
epochNum := x.config.V2.FirstSwitchBlock.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.SwitchBlock) == 0 {
|
if parentHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) == 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.SwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
|
epochNum := x.config.V2.FirstSwitchBlock.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.SwitchBlock) == 0 {
|
if header.Number.Cmp(x.config.V2.FirstSwitchBlock) == 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.SwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
|
epochNum := x.config.V2.FirstSwitchBlock.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.SwitchBlock) == 0 {
|
if quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,11 @@ func (x *XDPoS_v2) timeoutHandler(blockChainReader consensus.ChainReader, timeou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Collect timeout, generate TC
|
// Collect timeout, generate TC
|
||||||
isThresholdReached, numberOfTimeoutsInPool, pooledTimeouts := x.timeoutPool.Add(timeout)
|
numberOfTimeoutsInPool, pooledTimeouts := x.timeoutPool.Add(timeout)
|
||||||
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
|
||||||
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)
|
||||||
|
|
@ -94,7 +95,7 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
if timeoutCert == nil {
|
if timeoutCert == nil {
|
||||||
log.Warn("[verifyTC] TC is Nil")
|
log.Warn("[verifyTC] TC is Nil")
|
||||||
return utils.ErrInvalidTC
|
return utils.ErrInvalidTC
|
||||||
} else if timeoutCert.Signatures == nil || (len(timeoutCert.Signatures) < x.config.V2.CertThreshold) {
|
} else if timeoutCert.Signatures == nil || (len(timeoutCert.Signatures) < x.config.V2.CurrentConfig.CertThreshold) {
|
||||||
log.Warn("[verifyTC] Invalid TC Signature is nil or empty", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures))
|
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
|
return utils.ErrInvalidTC
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +221,7 @@ func (x *XDPoS_v2) OnCountdownTimeout(time time.Time, chain interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
x.timeoutCount++
|
x.timeoutCount++
|
||||||
if x.timeoutCount%x.config.V2.TimeoutSyncThreshold == 0 {
|
if x.timeoutCount%x.config.V2.CurrentConfig.TimeoutSyncThreshold == 0 {
|
||||||
log.Warn("[OnCountdownTimeout] timeout sync threadhold reached, send syncInfo message")
|
log.Warn("[OnCountdownTimeout] timeout sync threadhold reached, send syncInfo message")
|
||||||
syncInfo := x.getSyncInfo()
|
syncInfo := x.getSyncInfo()
|
||||||
x.broadcastToBftChannel(syncInfo)
|
x.broadcastToBftChannel(syncInfo)
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ func (x *XDPoS_v2) verifyMsgSignature(signedHashToBeVerified common.Hash, signat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, signerAddress, fmt.Errorf("Masternodes list does not contain signer address, Signer address: %v", signerAddress.Hex())
|
return false, signerAddress, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) getExtraFields(header *types.Header) (*types.QuorumCert, types.Round, []common.Address, error) {
|
func (x *XDPoS_v2) getExtraFields(header *types.Header) (*types.QuorumCert, types.Round, []common.Address, error) {
|
||||||
|
|
@ -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.SwitchBlock) == 0 {
|
if header.Number.Cmp(x.config.V2.FirstSwitchBlock) == 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.SwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.MinePeriod) > header.Time.Uint64() {
|
if parent.Number.Uint64() > x.config.V2.FirstSwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.CurrentConfig.MinePeriod) > header.Time.Uint64() {
|
||||||
return utils.ErrInvalidTimestamp
|
return utils.ErrInvalidTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,12 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect vote
|
// Collect vote
|
||||||
thresholdReached, numberOfVotesInPool, pooledVotes := x.votePool.Add(voteMsg)
|
numberOfVotesInPool, pooledVotes := x.votePool.Add(voteMsg)
|
||||||
log.Debug("[voteHandler] collect votes", "number", numberOfVotesInPool)
|
log.Debug("[voteHandler] collect votes", "number", numberOfVotesInPool)
|
||||||
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
|
||||||
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))
|
||||||
|
|
||||||
|
|
@ -120,8 +122,10 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole
|
||||||
ProposedBlockInfo: v.ProposedBlockInfo,
|
ProposedBlockInfo: v.ProposedBlockInfo,
|
||||||
GapNumber: v.GapNumber,
|
GapNumber: v.GapNumber,
|
||||||
}), v.Signature, masternodes)
|
}), v.Signature, masternodes)
|
||||||
if !verified || err != nil {
|
if err != nil {
|
||||||
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "Error", err.Error(), "verified", verified)
|
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "Error", err.Error())
|
||||||
|
} else if !verified {
|
||||||
|
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "verified", verified)
|
||||||
} else {
|
} else {
|
||||||
signatureSlice[i] = v.Signature
|
signatureSlice[i] = v.Signature
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +145,7 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.CertThreshold {
|
if len(validSignatureSlice) < x.config.V2.CurrentConfig.CertThreshold {
|
||||||
log.Warn("[onVotePoolThresholdReached] Not enough valid signatures to generate QC", "VotesSignaturesAfterFilter", validSignatureSlice, "NumberOfValidVotes", len(validSignatureSlice), "NumberOfVotes", len(pooledVotes))
|
log.Warn("[onVotePoolThresholdReached] Not enough valid signatures to generate QC", "VotesSignaturesAfterFilter", validSignatureSlice, "NumberOfValidVotes", len(validSignatureSlice), "NumberOfVotes", len(pooledVotes))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,18 @@ type PoolObj interface {
|
||||||
PoolKey() string
|
PoolKey() string
|
||||||
}
|
}
|
||||||
type Pool struct {
|
type Pool struct {
|
||||||
objList map[string]map[common.Hash]PoolObj
|
objList map[string]map[common.Hash]PoolObj
|
||||||
threshold int
|
lock sync.RWMutex // Protects the pool fields
|
||||||
lock sync.RWMutex // Protects the pool fields
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPool(threshold int) *Pool {
|
func NewPool() *Pool {
|
||||||
return &Pool{
|
return &Pool{
|
||||||
objList: make(map[string]map[common.Hash]PoolObj),
|
objList: make(map[string]map[common.Hash]PoolObj),
|
||||||
threshold: threshold,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true if it has reached threshold
|
// return true if it has reached threshold
|
||||||
func (p *Pool) Add(obj PoolObj) (bool, int, map[common.Hash]PoolObj) {
|
func (p *Pool) Add(obj PoolObj) (int, map[common.Hash]PoolObj) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
poolKey := obj.PoolKey()
|
poolKey := obj.PoolKey()
|
||||||
|
|
@ -35,10 +33,7 @@ func (p *Pool) Add(obj PoolObj) (bool, int, map[common.Hash]PoolObj) {
|
||||||
}
|
}
|
||||||
objListKeyed[obj.Hash()] = obj
|
objListKeyed[obj.Hash()] = obj
|
||||||
numOfItems := len(objListKeyed)
|
numOfItems := len(objListKeyed)
|
||||||
if numOfItems >= p.threshold {
|
return numOfItems, objListKeyed
|
||||||
return true, numOfItems, objListKeyed
|
|
||||||
}
|
|
||||||
return false, numOfItems, objListKeyed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pool) Size(obj PoolObj) int {
|
func (p *Pool) Size(obj PoolObj) int {
|
||||||
|
|
@ -85,13 +80,6 @@ func (p *Pool) Clear() {
|
||||||
p.objList = make(map[string]map[common.Hash]PoolObj)
|
p.objList = make(map[string]map[common.Hash]PoolObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pool) SetThreshold(t int) {
|
|
||||||
p.lock.Lock()
|
|
||||||
defer p.lock.Unlock()
|
|
||||||
|
|
||||||
p.threshold = t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Pool) GetObjsByKey(poolKey string) []PoolObj {
|
func (p *Pool) GetObjsByKey(poolKey string) []PoolObj {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
|
|
|
||||||
|
|
@ -10,55 +10,50 @@ import (
|
||||||
func TestPoolAdd(t *testing.T) {
|
func TestPoolAdd(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
pool := NewPool(2) // 2 is the cert threshold
|
pool := NewPool()
|
||||||
timeout1 := types.Timeout{Round: 1, Signature: []byte{1}}
|
timeout1 := types.Timeout{Round: 1, Signature: []byte{1}}
|
||||||
timeout2 := types.Timeout{Round: 1, Signature: []byte{2}}
|
timeout2 := types.Timeout{Round: 1, Signature: []byte{2}}
|
||||||
timeout3 := types.Timeout{Round: 1, Signature: []byte{3}}
|
timeout3 := types.Timeout{Round: 1, Signature: []byte{3}}
|
||||||
timeout4 := types.Timeout{Round: 1, Signature: []byte{4}}
|
timeout4 := types.Timeout{Round: 1, Signature: []byte{4}}
|
||||||
thresholdReached, numOfItems, pooledTimeouts := pool.Add(&timeout1)
|
numOfItems, pooledTimeouts := pool.Add(&timeout1)
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
assert.Equal(1, numOfItems)
|
assert.Equal(1, numOfItems)
|
||||||
assert.False(thresholdReached)
|
numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
assert.False(thresholdReached)
|
|
||||||
// Duplicates should not be added
|
// Duplicates should not be added
|
||||||
assert.Equal(1, numOfItems)
|
assert.Equal(1, numOfItems)
|
||||||
|
|
||||||
// Should add the one that is not a duplicates
|
// Should add the one that is not a duplicates
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
||||||
assert.True(thresholdReached)
|
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
assert.Equal(2, numOfItems)
|
assert.Equal(2, numOfItems)
|
||||||
|
|
||||||
// Try to add one more to the same round, it should also trigger threshold
|
// Try to add one more to the same round, it should also trigger threshold
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
||||||
assert.True(thresholdReached)
|
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
assert.Equal(3, numOfItems)
|
assert.Equal(3, numOfItems)
|
||||||
|
|
||||||
// Only after manually clearned the pool at its objKey, we shall not have any value for this particular key
|
// Only after manually clearned the pool at its objKey, we shall not have any value for this particular key
|
||||||
pool.ClearPoolKeyByObj(&timeout3)
|
pool.ClearPoolKeyByObj(&timeout3)
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout4)
|
numOfItems, pooledTimeouts = pool.Add(&timeout4)
|
||||||
assert.False(thresholdReached)
|
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
assert.Equal(1, numOfItems)
|
assert.Equal(1, numOfItems)
|
||||||
|
|
||||||
pool = NewPool(3) // 3 is the cert size
|
pool = NewPool()
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
||||||
assert.False(thresholdReached)
|
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
assert.Equal(1, numOfItems)
|
assert.Equal(1, numOfItems)
|
||||||
|
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
||||||
assert.False(thresholdReached)
|
|
||||||
assert.Equal(2, numOfItems)
|
assert.Equal(2, numOfItems)
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
pool.Clear()
|
pool.Clear()
|
||||||
|
|
||||||
// Pool has been cleared. Start from 0 again
|
// Pool has been cleared. Start from 0 again
|
||||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
||||||
assert.False(thresholdReached)
|
|
||||||
assert.Equal(1, numOfItems)
|
assert.Equal(1, numOfItems)
|
||||||
assert.NotNil(pooledTimeouts)
|
assert.NotNil(pooledTimeouts)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 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.SwitchBlock, big.NewInt(1))
|
headerV2.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, 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.SwitchBlock),
|
Number: big.NewInt(0).Set(blockchain.Config().XDPoS.V2.FirstSwitchBlock),
|
||||||
}
|
}
|
||||||
quorumCert := &types.QuorumCert{
|
quorumCert := &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.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.SwitchBlock, big.NewInt(1))
|
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, 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.SwitchBlock, big.NewInt(1)),
|
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(1)),
|
||||||
}
|
}
|
||||||
quorumCert = &types.QuorumCert{
|
quorumCert = &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.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.SwitchBlock, big.NewInt(2))
|
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, 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.SwitchBlock, big.NewInt(100)),
|
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(100)),
|
||||||
}
|
}
|
||||||
quorumCert = &types.QuorumCert{
|
quorumCert = &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.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.SwitchBlock, big.NewInt(101))
|
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, 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.SwitchBlock, big.NewInt(100)),
|
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, big.NewInt(100)),
|
||||||
}
|
}
|
||||||
quorumCert = &types.QuorumCert{
|
quorumCert = &types.QuorumCert{
|
||||||
ProposedBlockInfo: parentBlockInfo,
|
ProposedBlockInfo: parentBlockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.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.SwitchBlock, big.NewInt(101))
|
header.Number.Add(blockchain.Config().XDPoS.V2.FirstSwitchBlock, 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)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package engine_v2_tests
|
package engine_v2_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -33,21 +34,23 @@ func TestIsAuthorisedMNForConsensusV2(t *testing.T) {
|
||||||
func TestIsYourTurnConsensusV2(t *testing.T) {
|
func TestIsYourTurnConsensusV2(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, 900, params.TestXDPoSMockChainConfig, nil)
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 900, params.TestXDPoSMockChainConfig, nil)
|
||||||
minePeriod := params.TestXDPoSV2Config.MinePeriod
|
minePeriod := params.TestV2Configs[0].MinePeriod
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
blockNum := 901
|
blockNum := 901
|
||||||
blockCoinBase := "0x111000000000000000000000000000000123"
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 1, blockCoinBase, signer, signFn, nil, nil)
|
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 1, blockCoinBase, signer, signFn, nil, nil)
|
||||||
|
currentBlockHeader := currentBlock.Header()
|
||||||
|
currentBlockHeader.Time = big.NewInt(time.Now().Unix())
|
||||||
err := blockchain.InsertBlock(currentBlock)
|
err := blockchain.InsertBlock(currentBlock)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// Less then Mine Period
|
// Less then Mine Period
|
||||||
isYourTurn, err := adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
isYourTurn, err := adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.False(t, isYourTurn)
|
assert.False(t, isYourTurn)
|
||||||
|
|
||||||
time.Sleep(time.Duration(minePeriod) * time.Second)
|
time.Sleep(time.Duration(minePeriod) * time.Second)
|
||||||
// The second address is valid as the round starting from 1
|
// The second address is valid as the round starting from 1
|
||||||
isYourTurn, err = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.True(t, isYourTurn)
|
assert.True(t, isYourTurn)
|
||||||
|
|
||||||
|
|
@ -77,3 +80,30 @@ func TestIsYourTurnConsensusV2(t *testing.T) {
|
||||||
assert.False(t, isYourTurn)
|
assert.False(t, isYourTurn)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) {
|
||||||
|
// 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)
|
||||||
|
firstMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
|
||||||
|
|
||||||
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
blockNum := 911 // 911 is new config switch block
|
||||||
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
|
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 1, blockCoinBase, signer, signFn, nil, nil)
|
||||||
|
currentBlockHeader := currentBlock.Header()
|
||||||
|
currentBlockHeader.Time = big.NewInt(time.Now().Unix())
|
||||||
|
err := blockchain.InsertBlock(currentBlock)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// after first mine period
|
||||||
|
time.Sleep(time.Duration(firstMinePeriod) * time.Second)
|
||||||
|
isYourTurn, err := adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.False(t, isYourTurn)
|
||||||
|
|
||||||
|
// after new mine period
|
||||||
|
secondMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
|
||||||
|
time.Sleep(time.Duration(secondMinePeriod-firstMinePeriod) * time.Second)
|
||||||
|
isYourTurn, err = adaptor.YourTurn(blockchain, currentBlockHeader, common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e"))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, isYourTurn)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,11 +177,11 @@ func TestForensicsMonitoringNotOnSameChainButHaveSameRoundQC(t *testing.T) {
|
||||||
assert.Equal(t, types.Round(13), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
assert.Equal(t, types.Round(13), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
||||||
assert.Equal(t, uint64(913), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
assert.Equal(t, uint64(913), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||||
assert.Equal(t, 9, len(content.SmallerRoundInfo.HashPath))
|
assert.Equal(t, 9, len(content.SmallerRoundInfo.HashPath))
|
||||||
assert.Equal(t, 4, len(content.SmallerRoundInfo.SignerAddresses))
|
assert.Equal(t, 5, len(content.SmallerRoundInfo.SignerAddresses))
|
||||||
assert.Equal(t, types.Round(13), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
assert.Equal(t, types.Round(13), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
||||||
assert.Equal(t, uint64(912), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
assert.Equal(t, uint64(912), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||||
assert.Equal(t, 8, len(content.LargerRoundInfo.HashPath))
|
assert.Equal(t, 8, len(content.LargerRoundInfo.HashPath))
|
||||||
assert.Equal(t, 4, len(content.LargerRoundInfo.SignerAddresses))
|
assert.Equal(t, 5, len(content.LargerRoundInfo.SignerAddresses))
|
||||||
return
|
return
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -237,7 +237,7 @@ func TestForensicsMonitoringNotOnSameChainDoNotHaveSameRoundQC(t *testing.T) {
|
||||||
assert.Equal(t, types.Round(14), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
assert.Equal(t, types.Round(14), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
||||||
assert.Equal(t, uint64(914), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
assert.Equal(t, uint64(914), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||||
assert.Equal(t, 10, len(content.SmallerRoundInfo.HashPath))
|
assert.Equal(t, 10, len(content.SmallerRoundInfo.HashPath))
|
||||||
assert.Equal(t, 4, len(content.SmallerRoundInfo.SignerAddresses))
|
assert.Equal(t, 5, len(content.SmallerRoundInfo.SignerAddresses))
|
||||||
assert.Equal(t, types.Round(16), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
assert.Equal(t, types.Round(16), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
||||||
assert.Equal(t, uint64(906), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
assert.Equal(t, uint64(906), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||||
assert.Equal(t, 2, len(content.LargerRoundInfo.HashPath))
|
assert.Equal(t, 2, len(content.LargerRoundInfo.HashPath))
|
||||||
|
|
@ -300,7 +300,7 @@ func TestForensicsAcrossEpoch(t *testing.T) {
|
||||||
assert.Equal(t, types.Round(900), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
assert.Equal(t, types.Round(900), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
||||||
assert.Equal(t, uint64(1800), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
assert.Equal(t, uint64(1800), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||||
assert.Equal(t, 10, len(content.SmallerRoundInfo.HashPath))
|
assert.Equal(t, 10, len(content.SmallerRoundInfo.HashPath))
|
||||||
assert.Equal(t, 4, len(content.SmallerRoundInfo.SignerAddresses))
|
assert.Equal(t, 5, len(content.SmallerRoundInfo.SignerAddresses))
|
||||||
assert.Equal(t, types.Round(902), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
assert.Equal(t, types.Round(902), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Round)
|
||||||
assert.Equal(t, uint64(1792), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
assert.Equal(t, uint64(1792), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||||
assert.Equal(t, 2, len(content.LargerRoundInfo.HashPath))
|
assert.Equal(t, 2, len(content.LargerRoundInfo.HashPath))
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ var (
|
||||||
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
||||||
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
acc4Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f292")
|
||||||
|
acc5Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f293")
|
||||||
voterKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
|
voterKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
|
||||||
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) //xdc703c4b2bD70c169f5717101CaeE543299Fc946C7
|
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) //xdc703c4b2bD70c169f5717101CaeE543299Fc946C7
|
||||||
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) //xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
|
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) //xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
|
||||||
|
|
@ -310,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.SwitchBlock.Int64() {
|
if int64(i) > chainConfig.XDPoS.V2.FirstSwitchBlock.Int64() {
|
||||||
blockCoinBase = signer.Hex()
|
blockCoinBase = signer.Hex()
|
||||||
}
|
}
|
||||||
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
|
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.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)
|
||||||
|
|
@ -346,7 +348,7 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
||||||
}
|
}
|
||||||
|
|
||||||
// First v2 block
|
// First v2 block
|
||||||
if (int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()) == 1 {
|
if (int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.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)
|
||||||
|
|
@ -396,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.SwitchBlock.Int64() {
|
if int64(i) > chainConfig.XDPoS.V2.FirstSwitchBlock.Int64() {
|
||||||
blockCoinBase = signer.Hex()
|
blockCoinBase = signer.Hex()
|
||||||
}
|
}
|
||||||
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
|
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.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)
|
||||||
|
|
||||||
|
|
@ -424,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.SwitchBlock) == 1 { // Build engine v2 compatible extra data field
|
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 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{
|
||||||
|
|
@ -434,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.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
|
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
|
||||||
// Get last master node list from last v1 block
|
// Get last master node list from last v1 block
|
||||||
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.SwitchBlock.Uint64())
|
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.FirstSwitchBlock.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[:]...)
|
||||||
|
|
@ -444,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.SwitchBlock.Uint64())
|
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.FirstSwitchBlock.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[:]...)
|
||||||
|
|
@ -463,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.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
|
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 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 {
|
||||||
|
|
@ -522,7 +524,7 @@ func createBlockFromHeader(bc *BlockChain, customHeader *types.Header, txs []*ty
|
||||||
Difficulty: difficulty,
|
Difficulty: difficulty,
|
||||||
Number: customHeader.Number,
|
Number: customHeader.Number,
|
||||||
GasLimit: 1200000000,
|
GasLimit: 1200000000,
|
||||||
Time: big.NewInt(time.Now().Unix()),
|
Time: big.NewInt(time.Now().Unix() - 1000000 + int64(customHeader.Number.Uint64()*10)),
|
||||||
Extra: customHeader.Extra,
|
Extra: customHeader.Extra,
|
||||||
Validator: customHeader.Validator,
|
Validator: customHeader.Validator,
|
||||||
Validators: customHeader.Validators,
|
Validators: customHeader.Validators,
|
||||||
|
|
@ -582,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.SwitchBlock) > 0 {
|
if header.Number.Cmp(config.XDPoS.V2.FirstSwitchBlock) > 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 {
|
||||||
|
|
@ -659,7 +661,7 @@ func generateV2Extra(roundNumber int64, currentBlock *types.Block, signer common
|
||||||
var signatures []types.Signature
|
var signatures []types.Signature
|
||||||
if len(accKeys) == 0 {
|
if len(accKeys) == 0 {
|
||||||
// Sign from acc 1, 2, 3 by default
|
// Sign from acc 1, 2, 3 by default
|
||||||
accKeys = append(accKeys, acc1Key, acc2Key, acc3Key)
|
accKeys = append(accKeys, acc1Key, acc2Key, acc3Key, voterKey)
|
||||||
}
|
}
|
||||||
for _, acc := range accKeys {
|
for _, acc := range accKeys {
|
||||||
h := SignHashByPK(acc, types.VoteSigHash(voteForSign).Bytes())
|
h := SignHashByPK(acc, types.VoteSigHash(voteForSign).Bytes())
|
||||||
|
|
|
||||||
|
|
@ -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.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.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)
|
||||||
|
|
@ -43,10 +43,10 @@ func TestInitialFirstV2Blcok(t *testing.T) {
|
||||||
assert.Equal(t, uint64(450), snap.Number)
|
assert.Equal(t, uint64(450), snap.Number)
|
||||||
|
|
||||||
// Test Running channels
|
// Test Running channels
|
||||||
WaitPeriod := <-adaptor.WaitPeriodCh
|
waitPeriod := <-adaptor.WaitPeriodCh
|
||||||
assert.Equal(t, params.TestXDPoSMockChainConfig.XDPoS.V2.WaitPeriod, WaitPeriod)
|
assert.Equal(t, params.TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig.WaitPeriod, waitPeriod)
|
||||||
|
|
||||||
t.Logf("Waiting %d secs for timeout to happen", params.TestXDPoSMockChainConfig.XDPoS.V2.TimeoutPeriod)
|
t.Logf("Waiting %d secs for timeout to happen", params.TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig.TimeoutPeriod)
|
||||||
timeoutMsg := <-adaptor.EngineV2.BroadcastCh
|
timeoutMsg := <-adaptor.EngineV2.BroadcastCh
|
||||||
assert.NotNil(t, timeoutMsg)
|
assert.NotNil(t, timeoutMsg)
|
||||||
assert.Equal(t, types.Round(1), timeoutMsg.(*types.Timeout).Round)
|
assert.Equal(t, types.Round(1), timeoutMsg.(*types.Timeout).Round)
|
||||||
|
|
@ -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.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
|
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.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)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import (
|
||||||
func TestYourTurnInitialV2(t *testing.T) {
|
func TestYourTurnInitialV2(t *testing.T) {
|
||||||
config := params.TestXDPoSMockChainConfig
|
config := params.TestXDPoSMockChainConfig
|
||||||
blockchain, _, parentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)-1, config, nil)
|
blockchain, _, parentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)-1, config, nil)
|
||||||
minePeriod := config.XDPoS.V2.MinePeriod
|
minePeriod := config.XDPoS.V2.CurrentConfig.MinePeriod
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
||||||
// Insert block 900
|
// Insert block 900
|
||||||
|
|
@ -64,7 +64,7 @@ func TestShouldMineOncePerRound(t *testing.T) {
|
||||||
config := params.TestXDPoSMockChainConfig
|
config := params.TestXDPoSMockChainConfig
|
||||||
blockchain, _, block910, signer, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, config, nil)
|
blockchain, _, block910, signer, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, config, nil)
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
minePeriod := config.XDPoS.V2.MinePeriod
|
minePeriod := config.XDPoS.V2.CurrentConfig.MinePeriod
|
||||||
|
|
||||||
// Make sure we seal the parentBlock 910
|
// Make sure we seal the parentBlock 910
|
||||||
_, err := adaptor.Seal(blockchain, block910, nil)
|
_, err := adaptor.Seal(blockchain, block910, nil)
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ func TestShouldNotSendVoteMessageIfAlreadyVoteForThisRound(t *testing.T) {
|
||||||
select {
|
select {
|
||||||
case <-engineV2.BroadcastCh:
|
case <-engineV2.BroadcastCh:
|
||||||
t.Fatal("Should not trigger vote")
|
t.Fatal("Should not trigger vote")
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(3 * time.Second):
|
||||||
// Shoud not trigger setNewRound
|
// Shoud not trigger setNewRound
|
||||||
round, _, _, _, highestVotedRound, _ = engineV2.GetPropertiesFaker()
|
round, _, _, _, highestVotedRound, _ = engineV2.GetPropertiesFaker()
|
||||||
assert.Equal(t, types.Round(6), round)
|
assert.Equal(t, types.Round(6), round)
|
||||||
|
|
@ -290,7 +290,7 @@ func TestShouldNotSendVoteMsgIfBlockInfoRoundNotEqualCurrentRound(t *testing.T)
|
||||||
select {
|
select {
|
||||||
case <-engineV2.BroadcastCh:
|
case <-engineV2.BroadcastCh:
|
||||||
t.Fatal("Should not trigger vote")
|
t.Fatal("Should not trigger vote")
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(3 * time.Second):
|
||||||
// Shoud not trigger setNewRound
|
// Shoud not trigger setNewRound
|
||||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||||
assert.Equal(t, types.Round(8), round)
|
assert.Equal(t, types.Round(8), round)
|
||||||
|
|
@ -334,7 +334,7 @@ func TestShouldNotSendVoteMsgIfBlockNotExtendedFromAncestor(t *testing.T) {
|
||||||
select {
|
select {
|
||||||
case <-engineV2.BroadcastCh:
|
case <-engineV2.BroadcastCh:
|
||||||
t.Fatal("Should not trigger vote")
|
t.Fatal("Should not trigger vote")
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(3 * time.Second):
|
||||||
// Shoud not trigger setNewRound
|
// Shoud not trigger setNewRound
|
||||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||||
assert.Equal(t, types.Round(7), round)
|
assert.Equal(t, types.Round(7), round)
|
||||||
|
|
|
||||||
|
|
@ -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.SwitchBlock.SetUint64(1800)
|
config.XDPoS.V2.FirstSwitchBlock.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.SwitchBlock.SetUint64(1800)
|
config.XDPoS.V2.FirstSwitchBlock.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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package engine_v2_tests
|
package engine_v2_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -41,11 +42,11 @@ func TestCountdownTimeoutNotToSendTimeoutMessageIfNotInMasternodeList(t *testing
|
||||||
select {
|
select {
|
||||||
case <-engineV2.BroadcastCh:
|
case <-engineV2.BroadcastCh:
|
||||||
t.Fatalf("Not suppose to receive timeout msg")
|
t.Fatalf("Not suppose to receive timeout msg")
|
||||||
case <-time.After(15 * time.Second): //Countdown is only 1s wait, let's wait for 3s here
|
case <-time.After(10 * time.Second): //Countdown is only 1s wait, let's wait for 3s here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSyncInfoAfterReachTimeoutSnycThreadhold(t *testing.T) {
|
func TestSyncInfoAfterReachTimeoutSyncThreadhold(t *testing.T) {
|
||||||
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 901, params.TestXDPoSMockChainConfig, nil)
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 901, params.TestXDPoSMockChainConfig, nil)
|
||||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||||
engineV2.SetNewRoundFaker(blockchain, 1, true)
|
engineV2.SetNewRoundFaker(blockchain, 1, true)
|
||||||
|
|
@ -83,8 +84,63 @@ func TestSyncInfoAfterReachTimeoutSnycThreadhold(t *testing.T) {
|
||||||
assert.Equal(t, 2, syncInfoCounter)
|
assert.Equal(t, 2, syncInfoCounter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTimeoutPeriodAndThreadholdConfigChange(t *testing.T) {
|
||||||
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 1799, params.TestXDPoSMockChainConfig, nil)
|
||||||
|
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||||
|
// engineV2.SetNewRoundFaker(blockchain, 1, true)
|
||||||
|
|
||||||
|
// Because messages are sending async and on random order, so use this way to test
|
||||||
|
var timeoutCounter, syncInfoCounter int
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
obj := <-engineV2.BroadcastCh
|
||||||
|
switch v := obj.(type) {
|
||||||
|
case *types.Timeout:
|
||||||
|
timeoutCounter++
|
||||||
|
case *types.SyncInfo:
|
||||||
|
syncInfoCounter++
|
||||||
|
default:
|
||||||
|
log.Error("Unknown message type received", "value", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 2, timeoutCounter)
|
||||||
|
assert.Equal(t, 1, syncInfoCounter)
|
||||||
|
|
||||||
|
// Create another block to trigger update parameters
|
||||||
|
blockNum := 1800
|
||||||
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
|
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 900, blockCoinBase, signer, signFn, nil, nil)
|
||||||
|
currentBlockHeader := currentBlock.Header()
|
||||||
|
currentBlockHeader.Time = big.NewInt(time.Now().Unix())
|
||||||
|
err := blockchain.InsertBlock(currentBlock)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
engineV2.UpdateParams() // it will be triggered automatically on the real code by other process
|
||||||
|
|
||||||
|
t.Log("waiting for another consecutive period")
|
||||||
|
// another consecutive period
|
||||||
|
t1 := time.Now()
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
obj := <-engineV2.BroadcastCh
|
||||||
|
switch v := obj.(type) {
|
||||||
|
case *types.Timeout:
|
||||||
|
timeoutCounter++
|
||||||
|
case *types.SyncInfo:
|
||||||
|
syncInfoCounter++
|
||||||
|
default:
|
||||||
|
log.Error("Unknown message type received", "value", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t2 := time.Now()
|
||||||
|
timediff := t2.Sub(t1).Seconds()
|
||||||
|
assert.Equal(t, 6, timeoutCounter)
|
||||||
|
assert.Equal(t, 2, syncInfoCounter)
|
||||||
|
assert.Less(t, timediff, float64(20))
|
||||||
|
}
|
||||||
|
|
||||||
// Timeout handler
|
// Timeout handler
|
||||||
func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
||||||
|
params.TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig = params.TestV2Configs[0]
|
||||||
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfig, nil)
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfig, nil)
|
||||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,6 @@ func TestShouldVerifyBlock(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// Enable verify
|
// Enable verify
|
||||||
config.XDPoS.V2.SkipV2Validation = false
|
config.XDPoS.V2.SkipV2Validation = false
|
||||||
// Skip the mining time validation by set mine time to 0
|
|
||||||
config.XDPoS.V2.MinePeriod = 0
|
|
||||||
// Block 901 is the first v2 block with round of 1
|
// Block 901 is the first v2 block with round of 1
|
||||||
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
@ -97,8 +95,9 @@ func TestShouldVerifyBlock(t *testing.T) {
|
||||||
err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true)
|
err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true)
|
||||||
assert.Equal(t, consensus.ErrUnknownAncestor, err)
|
assert.Equal(t, consensus.ErrUnknownAncestor, err)
|
||||||
|
|
||||||
|
block901 := blockchain.GetBlockByNumber(901).Header()
|
||||||
tooFastMinedBlock := blockchain.GetBlockByNumber(902).Header()
|
tooFastMinedBlock := blockchain.GetBlockByNumber(902).Header()
|
||||||
tooFastMinedBlock.Time = big.NewInt(time.Now().Unix() - 10)
|
tooFastMinedBlock.Time = big.NewInt(block901.Time.Int64() - 10)
|
||||||
err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true)
|
err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true)
|
||||||
assert.Equal(t, utils.ErrInvalidTimestamp, err)
|
assert.Equal(t, utils.ErrInvalidTimestamp, err)
|
||||||
|
|
||||||
|
|
@ -107,7 +106,7 @@ func TestShouldVerifyBlock(t *testing.T) {
|
||||||
err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true)
|
err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true)
|
||||||
assert.Equal(t, utils.ErrInvalidDifficulty, err)
|
assert.Equal(t, utils.ErrInvalidDifficulty, err)
|
||||||
|
|
||||||
// Creat an invalid QC round
|
// Create an invalid QC round
|
||||||
proposedBlockInfo := &types.BlockInfo{
|
proposedBlockInfo := &types.BlockInfo{
|
||||||
Hash: blockchain.GetBlockByNumber(902).Hash(),
|
Hash: blockchain.GetBlockByNumber(902).Hash(),
|
||||||
Round: types.Round(2),
|
Round: types.Round(2),
|
||||||
|
|
@ -169,6 +168,62 @@ func TestShouldVerifyBlock(t *testing.T) {
|
||||||
assert.Equal(t, utils.ErrPenaltiesNotLegit, err)
|
assert.Equal(t, utils.ErrPenaltiesNotLegit, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
|
||||||
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
configString := string(b)
|
||||||
|
|
||||||
|
var config params.ChainConfig
|
||||||
|
err = json.Unmarshal([]byte(configString), &config)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// Enable verify
|
||||||
|
config.XDPoS.V2.SkipV2Validation = false
|
||||||
|
// Block 901 is the first v2 block with round of 1
|
||||||
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 915, &config, nil)
|
||||||
|
|
||||||
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
||||||
|
// Genrate QC
|
||||||
|
proposedBlockInfo := &types.BlockInfo{
|
||||||
|
Hash: blockchain.GetBlockByNumber(911).Hash(),
|
||||||
|
Round: types.Round(11),
|
||||||
|
Number: blockchain.GetBlockByNumber(911).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 signatures []types.Signature
|
||||||
|
signatures = append(signatures, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
||||||
|
quorumCert := &types.QuorumCert{
|
||||||
|
ProposedBlockInfo: proposedBlockInfo,
|
||||||
|
Signatures: signatures,
|
||||||
|
GapNumber: 450,
|
||||||
|
}
|
||||||
|
|
||||||
|
extra := types.ExtraFields_v2{
|
||||||
|
Round: types.Round(12),
|
||||||
|
QuorumCert: quorumCert,
|
||||||
|
}
|
||||||
|
extraInBytes, err := 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
|
||||||
|
block912 := blockchain.GetBlockByNumber(912).Header()
|
||||||
|
block912.Extra = extraInBytes
|
||||||
|
err = adaptor.VerifyHeader(blockchain, block912, true)
|
||||||
|
|
||||||
|
// Error happens after verify QC, means verify QC passed
|
||||||
|
assert.Equal(t, utils.ErrInvalidQC, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
||||||
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
@ -179,8 +234,6 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// Enable verify
|
// Enable verify
|
||||||
config.XDPoS.V2.SkipV2Validation = false
|
config.XDPoS.V2.SkipV2Validation = false
|
||||||
// Skip the mining time validation by set mine time to 0
|
|
||||||
config.XDPoS.V2.MinePeriod = 0
|
|
||||||
// Block 901 is the first v2 block with round of 1
|
// Block 901 is the first v2 block with round of 1
|
||||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 902, &config, nil)
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 902, &config, nil)
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
@ -232,8 +285,6 @@ func TestShouldVerifyHeaders(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// Enable verify
|
// Enable verify
|
||||||
config.XDPoS.V2.SkipV2Validation = false
|
config.XDPoS.V2.SkipV2Validation = false
|
||||||
// Skip the mining time validation by set mine time to 0
|
|
||||||
config.XDPoS.V2.MinePeriod = 0
|
|
||||||
// Block 901 is the first v2 block with round of 1
|
// Block 901 is the first v2 block with round of 1
|
||||||
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
@ -273,8 +324,6 @@ func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
// Enable verify
|
// Enable verify
|
||||||
config.XDPoS.V2.SkipV2Validation = false
|
config.XDPoS.V2.SkipV2Validation = false
|
||||||
// Skip the mining time validation by set mine time to 0
|
|
||||||
config.XDPoS.V2.MinePeriod = 0
|
|
||||||
// Block 901 is the first v2 block with round of 1
|
// Block 901 is the first v2 block with round of 1
|
||||||
blockchain, _, block910, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
blockchain, _, block910, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
||||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
@ -283,12 +332,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.SwitchBlock.Int64()
|
roundNumber := int64(blockNumber) - config.XDPoS.V2.FirstSwitchBlock.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.SwitchBlock.Int64()
|
roundNumber = int64(blockNumber) - config.XDPoS.V2.FirstSwitchBlock.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.SwitchBlock != nil && header.Number.Cmp(bc.chainConfig.XDPoS.V2.SwitchBlock) == 1) {
|
if bc.chainConfig.IsTIPIncreaseMasternodes(header.Number) || (bc.chainConfig.XDPoS.V2.FirstSwitchBlock != nil && header.Number.Cmp(bc.chainConfig.XDPoS.V2.FirstSwitchBlock) == 1) {
|
||||||
// using new masterndoes
|
// using new masterndoes
|
||||||
maxMasternodes = common.MaxMasternodesV2
|
maxMasternodes = common.MaxMasternodesV2
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -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.SwitchBlock.Uint64()
|
comebackHeight := (common.LimitPenaltyEpochV2+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.FirstSwitchBlock.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.SwitchBlock.Uint64()+1 {
|
if number == chain.Config().XDPoS.V2.FirstSwitchBlock.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.SwitchBlock.Uint64()+1 {
|
if isEpochSwitch && i != chain.Config().XDPoS.V2.FirstSwitchBlock.Uint64()+1 {
|
||||||
epochCount += 1
|
epochCount += 1
|
||||||
if epochCount == signEpochCount {
|
if epochCount == signEpochCount {
|
||||||
endBlockNumber = header.Number.Uint64() - 1
|
endBlockNumber = header.Number.Uint64() - 1
|
||||||
|
|
|
||||||
|
|
@ -267,8 +267,7 @@ func (self *worker) update() {
|
||||||
defer self.chainSideSub.Unsubscribe()
|
defer self.chainSideSub.Unsubscribe()
|
||||||
|
|
||||||
// timeout waiting for v1 inital value
|
// timeout waiting for v1 inital value
|
||||||
// TODO: Read value from config after we decide where is the config
|
waitPeriod := 2
|
||||||
waitPeriod := 10
|
|
||||||
WaitPeriodCh := self.engine.(*XDPoS.XDPoS).WaitPeriodCh
|
WaitPeriodCh := self.engine.(*XDPoS.XDPoS).WaitPeriodCh
|
||||||
defer close(WaitPeriodCh)
|
defer close(WaitPeriodCh)
|
||||||
|
|
||||||
|
|
|
||||||
218
params/config.go
218
params/config.go
|
|
@ -26,6 +26,7 @@ import (
|
||||||
const (
|
const (
|
||||||
ConsensusEngineVersion1 = "v1"
|
ConsensusEngineVersion1 = "v1"
|
||||||
ConsensusEngineVersion2 = "v2"
|
ConsensusEngineVersion2 = "v2"
|
||||||
|
Default = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -36,30 +37,92 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
XDPoSV2Config = &V2{
|
MainnetV2Configs = map[uint64]*V2Config{
|
||||||
SwitchBlock: big.NewInt(9999999999),
|
Default: {
|
||||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
SwitchBlock: big.NewInt(9999999999),
|
||||||
TimeoutSyncThreshold: 3,
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
TimeoutPeriod: 60,
|
TimeoutSyncThreshold: 3,
|
||||||
WaitPeriod: 10,
|
TimeoutPeriod: 60,
|
||||||
MinePeriod: 10,
|
WaitPeriod: 10,
|
||||||
|
MinePeriod: 10,
|
||||||
|
},
|
||||||
|
9999999999: {
|
||||||
|
SwitchBlock: big.NewInt(9999999999),
|
||||||
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
|
TimeoutSyncThreshold: 3,
|
||||||
|
TimeoutPeriod: 60,
|
||||||
|
WaitPeriod: 10,
|
||||||
|
MinePeriod: 10,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
TestXDPoSV2Config = &V2{
|
TestV2Configs = map[uint64]*V2Config{
|
||||||
SwitchBlock: big.NewInt(900),
|
Default: {
|
||||||
CertThreshold: 3,
|
SwitchBlock: big.NewInt(900),
|
||||||
TimeoutSyncThreshold: 2,
|
CertThreshold: 3,
|
||||||
TimeoutPeriod: 10,
|
TimeoutSyncThreshold: 2,
|
||||||
WaitPeriod: 1,
|
TimeoutPeriod: 4,
|
||||||
MinePeriod: 2,
|
WaitPeriod: 1,
|
||||||
SkipV2Validation: true,
|
MinePeriod: 2,
|
||||||
|
},
|
||||||
|
900: {
|
||||||
|
SwitchBlock: big.NewInt(900),
|
||||||
|
CertThreshold: 3,
|
||||||
|
TimeoutSyncThreshold: 2,
|
||||||
|
TimeoutPeriod: 4,
|
||||||
|
WaitPeriod: 1,
|
||||||
|
MinePeriod: 2,
|
||||||
|
},
|
||||||
|
910: {
|
||||||
|
SwitchBlock: big.NewInt(910),
|
||||||
|
CertThreshold: 5,
|
||||||
|
TimeoutSyncThreshold: 2,
|
||||||
|
TimeoutPeriod: 4,
|
||||||
|
WaitPeriod: 2,
|
||||||
|
MinePeriod: 3,
|
||||||
|
},
|
||||||
|
1799: {
|
||||||
|
SwitchBlock: big.NewInt(1799),
|
||||||
|
CertThreshold: 5,
|
||||||
|
TimeoutSyncThreshold: 4,
|
||||||
|
TimeoutPeriod: 5,
|
||||||
|
WaitPeriod: 2,
|
||||||
|
MinePeriod: 3,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
DevnetXDPoSV2Config = &V2{
|
|
||||||
SwitchBlock: big.NewInt(7074000),
|
DevnetV2Configs = map[uint64]*V2Config{
|
||||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
Default: {
|
||||||
TimeoutSyncThreshold: 5,
|
SwitchBlock: big.NewInt(7074000),
|
||||||
TimeoutPeriod: 25,
|
CertThreshold: 4,
|
||||||
WaitPeriod: 10,
|
TimeoutSyncThreshold: 5,
|
||||||
MinePeriod: 10,
|
TimeoutPeriod: 10,
|
||||||
|
WaitPeriod: 5,
|
||||||
|
MinePeriod: 5,
|
||||||
|
},
|
||||||
|
7074000: {
|
||||||
|
SwitchBlock: big.NewInt(7074000),
|
||||||
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
|
TimeoutSyncThreshold: 5,
|
||||||
|
TimeoutPeriod: 25,
|
||||||
|
WaitPeriod: 10,
|
||||||
|
MinePeriod: 10,
|
||||||
|
},
|
||||||
|
9900000: {
|
||||||
|
SwitchBlock: big.NewInt(9900000),
|
||||||
|
CertThreshold: common.MaxMasternodesV2*3/5 + 1,
|
||||||
|
TimeoutSyncThreshold: 5,
|
||||||
|
TimeoutPeriod: 25,
|
||||||
|
WaitPeriod: 5,
|
||||||
|
MinePeriod: 20,
|
||||||
|
},
|
||||||
|
10000000: {
|
||||||
|
SwitchBlock: big.NewInt(10000000),
|
||||||
|
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||||
|
TimeoutSyncThreshold: 5,
|
||||||
|
TimeoutPeriod: 25,
|
||||||
|
WaitPeriod: 10,
|
||||||
|
MinePeriod: 10,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// XDPoSChain mainnet config
|
// XDPoSChain mainnet config
|
||||||
|
|
@ -78,7 +141,11 @@ var (
|
||||||
RewardCheckpoint: 900,
|
RewardCheckpoint: 900,
|
||||||
Gap: 450,
|
Gap: 450,
|
||||||
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
|
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
|
||||||
V2: XDPoSV2Config,
|
V2: &V2{
|
||||||
|
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
|
||||||
|
CurrentConfig: MainnetV2Configs[0],
|
||||||
|
AllConfigs: MainnetV2Configs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,11 +183,16 @@ var (
|
||||||
RewardCheckpoint: 900,
|
RewardCheckpoint: 900,
|
||||||
Gap: 450,
|
Gap: 450,
|
||||||
FoudationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"),
|
FoudationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"),
|
||||||
V2: TestXDPoSV2Config,
|
V2: &V2{
|
||||||
|
FirstSwitchBlock: TestV2Configs[0].SwitchBlock,
|
||||||
|
CurrentConfig: TestV2Configs[0],
|
||||||
|
AllConfigs: TestV2Configs,
|
||||||
|
SkipV2Validation: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
|
// DevnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
|
||||||
DevnetChainConfig = &ChainConfig{
|
DevnetChainConfig = &ChainConfig{
|
||||||
ChainId: big.NewInt(551),
|
ChainId: big.NewInt(551),
|
||||||
HomesteadBlock: big.NewInt(1),
|
HomesteadBlock: big.NewInt(1),
|
||||||
|
|
@ -136,7 +208,11 @@ var (
|
||||||
RewardCheckpoint: 900,
|
RewardCheckpoint: 900,
|
||||||
Gap: 450,
|
Gap: 450,
|
||||||
FoudationWalletAddr: common.HexToAddress("0x746249c61f5832c5eed53172776b460491bdcd5c"),
|
FoudationWalletAddr: common.HexToAddress("0x746249c61f5832c5eed53172776b460491bdcd5c"),
|
||||||
V2: DevnetXDPoSV2Config,
|
V2: &V2{
|
||||||
|
FirstSwitchBlock: DevnetV2Configs[0].SwitchBlock,
|
||||||
|
CurrentConfig: DevnetV2Configs[0],
|
||||||
|
AllConfigs: DevnetV2Configs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +231,11 @@ var (
|
||||||
XDPoS: &XDPoSConfig{
|
XDPoS: &XDPoSConfig{
|
||||||
Period: 15,
|
Period: 15,
|
||||||
Epoch: 30000,
|
Epoch: 30000,
|
||||||
V2: XDPoSV2Config,
|
V2: &V2{
|
||||||
|
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
|
||||||
|
CurrentConfig: MainnetV2Configs[0],
|
||||||
|
AllConfigs: MainnetV2Configs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,7 +255,32 @@ var (
|
||||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
|
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
|
||||||
|
|
||||||
// XDPoS config with v2 engine after block 901
|
// XDPoS config with v2 engine after block 901
|
||||||
TestXDPoSMockChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipV1Validation: true, V2: TestXDPoSV2Config, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), Reward: 250}}
|
TestXDPoSMockChainConfig = &ChainConfig{
|
||||||
|
big.NewInt(1337),
|
||||||
|
big.NewInt(0),
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
big.NewInt(0),
|
||||||
|
common.Hash{},
|
||||||
|
big.NewInt(0),
|
||||||
|
big.NewInt(0),
|
||||||
|
big.NewInt(0),
|
||||||
|
nil,
|
||||||
|
new(EthashConfig),
|
||||||
|
nil,
|
||||||
|
&XDPoSConfig{
|
||||||
|
Epoch: 900,
|
||||||
|
Gap: 450,
|
||||||
|
SkipV1Validation: true,
|
||||||
|
FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
|
||||||
|
Reward: 250,
|
||||||
|
V2: &V2{
|
||||||
|
FirstSwitchBlock: TestV2Configs[0].SwitchBlock,
|
||||||
|
CurrentConfig: TestV2Configs[0],
|
||||||
|
AllConfigs: TestV2Configs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
|
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||||
|
|
@ -242,28 +347,69 @@ type XDPoSConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type V2 struct {
|
type V2 struct {
|
||||||
|
FirstSwitchBlock *big.Int `json:"switchBlock"`
|
||||||
|
CurrentConfig *V2Config `json:"config"`
|
||||||
|
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 {
|
||||||
WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event
|
WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event
|
||||||
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
|
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
|
||||||
SwitchBlock *big.Int `json:"switchBlock"` // v1 to v2 switch block number
|
SwitchBlock *big.Int `json:"switchBlock"` // v1 to v2 switch block number
|
||||||
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
|
||||||
SkipV2Validation bool //Skip Block Validation for testing purpose, V2 consensus only
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the stringer interface, returning the consensus engine details.
|
// String implements the stringer interface, returning the consensus engine details.
|
||||||
|
func (c *XDPoSConfig) BuildConfigIndex() {
|
||||||
|
var list []uint64
|
||||||
|
|
||||||
|
for i := range c.V2.AllConfigs {
|
||||||
|
list = append(list, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort, sort lib doesn't support type uint64, it's ok to have O(n^2) because only few items in the list
|
||||||
|
for i := 0; i < len(list)-1; i++ {
|
||||||
|
for j := i + 1; j < len(list); j++ {
|
||||||
|
if list[i] > list[j] {
|
||||||
|
list[i], list[j] = list[j], list[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.V2.configIndex = list
|
||||||
|
}
|
||||||
|
|
||||||
func (c *XDPoSConfig) String() string {
|
func (c *XDPoSConfig) String() string {
|
||||||
return "XDPoS"
|
return "XDPoS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
func (c *XDPoSConfig) BlockConsensusVersion(num *big.Int, extraByte []byte, skipExtraCheck bool) string {
|
||||||
if c.V2 != nil && c.V2.SwitchBlock != nil && num.Cmp(c.V2.SwitchBlock) > 0 {
|
if !skipExtraCheck && (len(extraByte) == 0 || extraByte[0] != 2) {
|
||||||
if skipExtraCheck {
|
return ConsensusEngineVersion1
|
||||||
return ConsensusEngineVersion2
|
}
|
||||||
}
|
|
||||||
if len(extraByte) == 0 || extraByte[0] != 2 {
|
if c.V2 != nil && c.V2.FirstSwitchBlock != nil && num.Cmp(c.V2.FirstSwitchBlock) > 0 {
|
||||||
return ConsensusEngineVersion1
|
// 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 ConsensusEngineVersion2
|
||||||
}
|
}
|
||||||
return ConsensusEngineVersion1
|
return ConsensusEngineVersion1
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue