mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 13:21:37 +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 {
|
||||
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() {
|
||||
started := false
|
||||
ok := false
|
||||
|
|
@ -345,6 +345,8 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
|
|||
defer close(core.CheckpointCh)
|
||||
for range core.CheckpointCh {
|
||||
log.Info("Checkpoint!!! It's time to reconcile node's state...")
|
||||
log.Info("Update consensus parameters")
|
||||
engine.UpdateParams()
|
||||
if common.IsTestnet {
|
||||
ok, err = ethereum.ValidateMasternodeTestnet()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ func (t *CountdownTimer) StopTimer() {
|
|||
<-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`
|
||||
func (t *CountdownTimer) Reset(i interface{}) {
|
||||
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
|
||||
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)
|
||||
|
|
@ -140,6 +144,11 @@ func NewFaker(db ethdb.Database, chainConfig *params.ChainConfig) *XDPoS {
|
|||
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 {
|
||||
switch x.config.BlockConsensusVersion(header.Number, header.Extra, ExtraFieldCheck) {
|
||||
case params.ConsensusEngineVersion2:
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ type XDPoS_v2 struct {
|
|||
|
||||
func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 {
|
||||
// Setup timeoutTimer
|
||||
duration := time.Duration(config.V2.TimeoutPeriod) * time.Second
|
||||
duration := time.Duration(config.V2.CurrentConfig.TimeoutPeriod) * time.Second
|
||||
timeoutTimer := countdown.NewCountDown(duration)
|
||||
|
||||
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))
|
||||
verifiedHeaders, _ := lru.NewARC(utils.InmemorySnapshots)
|
||||
|
||||
timeoutPool := utils.NewPool(config.V2.CertThreshold)
|
||||
votePool := utils.NewPool(config.V2.CertThreshold)
|
||||
timeoutPool := utils.NewPool()
|
||||
votePool := utils.NewPool()
|
||||
engine := &XDPoS_v2{
|
||||
config: config,
|
||||
db: db,
|
||||
|
|
@ -116,6 +116,7 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *
|
|||
timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout
|
||||
|
||||
engine.periodicJob()
|
||||
config.BuildConfigIndex()
|
||||
|
||||
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
|
||||
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) {
|
||||
return sigHash(header)
|
||||
}
|
||||
|
|
@ -150,7 +163,7 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
|||
var quorumCert *types.QuorumCert
|
||||
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")
|
||||
blockInfo := &types.BlockInfo{
|
||||
Hash: header.Hash(),
|
||||
|
|
@ -180,13 +193,13 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
|||
}
|
||||
|
||||
// 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)
|
||||
|
||||
snap, _ := loadSnapshot(x.db, lastGapHeader.Hash())
|
||||
|
||||
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")
|
||||
_, _, masternodes, err := x.getExtraFields(checkpointHeader)
|
||||
|
|
@ -204,10 +217,10 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
|
|||
}
|
||||
|
||||
// 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
|
||||
go func() {
|
||||
x.waitPeriodCh <- x.config.V2.WaitPeriod
|
||||
x.waitPeriodCh <- x.config.V2.CurrentConfig.WaitPeriod
|
||||
}()
|
||||
|
||||
// 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()
|
||||
if waitedTime < int64(x.config.V2.MinePeriod) {
|
||||
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.MinePeriod, "waitedTime", waitedTime)
|
||||
if waitedTime < int64(x.config.V2.CurrentConfig.MinePeriod) {
|
||||
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.CurrentConfig.MinePeriod, "waitedTime", waitedTime)
|
||||
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
|
||||
if blockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||
if blockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 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)
|
||||
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 {
|
||||
log.Warn("[verifyQC] QC is Nil")
|
||||
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
|
||||
log.Warn("[verifyHeader] Invalid QC Signature is nil or empty", "QC", quorumCert, "QCNumber", quorumCert.ProposedBlockInfo.Number, "Signatures len", len(signatures))
|
||||
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)
|
||||
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
|
||||
proposedBlockQuorumCert, round, _, err := x.getExtraFields(proposedBlockHeader)
|
||||
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)
|
||||
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
|
||||
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
|
||||
}
|
||||
// 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
|
||||
|
||||
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")
|
||||
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
|
||||
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 parentHeader.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||
if parentHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
||||
return true, epochNum, nil
|
||||
}
|
||||
|
||||
|
|
@ -111,13 +111,13 @@ func (x *XDPoS_v2) GetCurrentEpochSwitchBlock(chain consensus.ChainReader, block
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
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")
|
||||
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
|
||||
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 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())
|
||||
return true, epochNum, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ func (x *XDPoS_v2) timeoutHandler(blockChainReader consensus.ChainReader, timeou
|
|||
}
|
||||
}
|
||||
// Collect timeout, generate TC
|
||||
isThresholdReached, numberOfTimeoutsInPool, pooledTimeouts := x.timeoutPool.Add(timeout)
|
||||
numberOfTimeoutsInPool, pooledTimeouts := x.timeoutPool.Add(timeout)
|
||||
log.Debug("[timeoutHandler] collect timeout", "number", numberOfTimeoutsInPool)
|
||||
|
||||
// Threshold reached
|
||||
isThresholdReached := numberOfTimeoutsInPool >= x.config.V2.CurrentConfig.CertThreshold
|
||||
if isThresholdReached {
|
||||
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)
|
||||
|
|
@ -94,7 +95,7 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
|||
if timeoutCert == nil {
|
||||
log.Warn("[verifyTC] TC is Nil")
|
||||
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))
|
||||
return utils.ErrInvalidTC
|
||||
}
|
||||
|
|
@ -220,7 +221,7 @@ func (x *XDPoS_v2) OnCountdownTimeout(time time.Time, chain interface{}) error {
|
|||
}
|
||||
|
||||
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")
|
||||
syncInfo := x.getSyncInfo()
|
||||
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) {
|
||||
|
|
@ -127,7 +127,7 @@ func (x *XDPoS_v2) getExtraFields(header *types.Header) (*types.QuorumCert, type
|
|||
var masternodes []common.Address
|
||||
|
||||
// last v1 block
|
||||
if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
|
||||
if header.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
|
||||
masternodes = decodeMasternodesFromHeaderExtra(header)
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,10 +70,12 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
|
|||
}
|
||||
|
||||
// Collect vote
|
||||
thresholdReached, numberOfVotesInPool, pooledVotes := x.votePool.Add(voteMsg)
|
||||
numberOfVotesInPool, pooledVotes := x.votePool.Add(voteMsg)
|
||||
log.Debug("[voteHandler] collect votes", "number", numberOfVotesInPool)
|
||||
go x.ForensicsProcessor.DetectEquivocationInVotePool(voteMsg, x.votePool)
|
||||
go x.ForensicsProcessor.ProcessVoteEquivocation(chain, x, voteMsg)
|
||||
|
||||
thresholdReached := numberOfVotesInPool >= x.config.V2.CurrentConfig.CertThreshold
|
||||
if thresholdReached {
|
||||
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,
|
||||
GapNumber: v.GapNumber,
|
||||
}), v.Signature, masternodes)
|
||||
if !verified || err != nil {
|
||||
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "Error", err.Error(), "verified", verified)
|
||||
if err != nil {
|
||||
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 {
|
||||
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
|
||||
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))
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,20 +11,18 @@ type PoolObj interface {
|
|||
PoolKey() string
|
||||
}
|
||||
type Pool struct {
|
||||
objList map[string]map[common.Hash]PoolObj
|
||||
threshold int
|
||||
lock sync.RWMutex // Protects the pool fields
|
||||
objList map[string]map[common.Hash]PoolObj
|
||||
lock sync.RWMutex // Protects the pool fields
|
||||
}
|
||||
|
||||
func NewPool(threshold int) *Pool {
|
||||
func NewPool() *Pool {
|
||||
return &Pool{
|
||||
objList: make(map[string]map[common.Hash]PoolObj),
|
||||
threshold: threshold,
|
||||
objList: make(map[string]map[common.Hash]PoolObj),
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
defer p.lock.Unlock()
|
||||
poolKey := obj.PoolKey()
|
||||
|
|
@ -35,10 +33,7 @@ func (p *Pool) Add(obj PoolObj) (bool, int, map[common.Hash]PoolObj) {
|
|||
}
|
||||
objListKeyed[obj.Hash()] = obj
|
||||
numOfItems := len(objListKeyed)
|
||||
if numOfItems >= p.threshold {
|
||||
return true, numOfItems, objListKeyed
|
||||
}
|
||||
return false, numOfItems, objListKeyed
|
||||
return numOfItems, objListKeyed
|
||||
}
|
||||
|
||||
func (p *Pool) Size(obj PoolObj) int {
|
||||
|
|
@ -85,13 +80,6 @@ func (p *Pool) Clear() {
|
|||
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 {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
|
|
|||
|
|
@ -10,55 +10,50 @@ import (
|
|||
func TestPoolAdd(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
pool := NewPool(2) // 2 is the cert threshold
|
||||
pool := NewPool()
|
||||
timeout1 := types.Timeout{Round: 1, Signature: []byte{1}}
|
||||
timeout2 := types.Timeout{Round: 1, Signature: []byte{2}}
|
||||
timeout3 := types.Timeout{Round: 1, Signature: []byte{3}}
|
||||
timeout4 := types.Timeout{Round: 1, Signature: []byte{4}}
|
||||
thresholdReached, numOfItems, pooledTimeouts := pool.Add(&timeout1)
|
||||
numOfItems, pooledTimeouts := pool.Add(&timeout1)
|
||||
assert.NotNil(pooledTimeouts)
|
||||
assert.Equal(1, numOfItems)
|
||||
assert.False(thresholdReached)
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
||||
assert.NotNil(pooledTimeouts)
|
||||
assert.False(thresholdReached)
|
||||
// Duplicates should not be added
|
||||
assert.Equal(1, numOfItems)
|
||||
|
||||
// Should add the one that is not a duplicates
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
||||
assert.True(thresholdReached)
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
||||
|
||||
assert.NotNil(pooledTimeouts)
|
||||
assert.Equal(2, numOfItems)
|
||||
|
||||
// Try to add one more to the same round, it should also trigger threshold
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
||||
assert.True(thresholdReached)
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
||||
assert.NotNil(pooledTimeouts)
|
||||
assert.Equal(3, numOfItems)
|
||||
|
||||
// Only after manually clearned the pool at its objKey, we shall not have any value for this particular key
|
||||
pool.ClearPoolKeyByObj(&timeout3)
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout4)
|
||||
assert.False(thresholdReached)
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout4)
|
||||
|
||||
assert.NotNil(pooledTimeouts)
|
||||
assert.Equal(1, numOfItems)
|
||||
|
||||
pool = NewPool(3) // 3 is the cert size
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
||||
assert.False(thresholdReached)
|
||||
pool = NewPool()
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout1)
|
||||
assert.NotNil(pooledTimeouts)
|
||||
assert.Equal(1, numOfItems)
|
||||
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
||||
assert.False(thresholdReached)
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout2)
|
||||
|
||||
assert.Equal(2, numOfItems)
|
||||
assert.NotNil(pooledTimeouts)
|
||||
pool.Clear()
|
||||
|
||||
// Pool has been cleared. Start from 0 again
|
||||
thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
||||
assert.False(thresholdReached)
|
||||
numOfItems, pooledTimeouts = pool.Add(&timeout3)
|
||||
assert.Equal(1, numOfItems)
|
||||
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)
|
||||
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
|
||||
header.Extra = []byte{}
|
||||
if len(header.Extra) < utils.ExtraVanity {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func TestAdaptorGetMasternodesFromCheckpointHeader(t *testing.T) {
|
|||
headerV1.Extra = common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400")
|
||||
masternodesV1 := adaptor.GetMasternodesFromCheckpointHeader(headerV1)
|
||||
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.Extra = []byte{2}
|
||||
masternodesV2 := adaptor.GetMasternodesFromCheckpointHeader(headerV2)
|
||||
|
|
@ -91,12 +91,12 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
parentBlockInfo := &types.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
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{
|
||||
ProposedBlockInfo: parentBlockInfo,
|
||||
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{
|
||||
Round: 1,
|
||||
|
|
@ -105,19 +105,19 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
extraBytes, err := extra.EncodeToBytes()
|
||||
assert.Nil(t, err)
|
||||
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)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||
parentBlockInfo = &types.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
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{
|
||||
ProposedBlockInfo: parentBlockInfo,
|
||||
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{
|
||||
Round: 2,
|
||||
|
|
@ -126,19 +126,19 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
extraBytes, err = extra.EncodeToBytes()
|
||||
assert.Nil(t, err)
|
||||
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)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||
parentBlockInfo = &types.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
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{
|
||||
ProposedBlockInfo: parentBlockInfo,
|
||||
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{
|
||||
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 1,
|
||||
|
|
@ -147,19 +147,19 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
extraBytes, err = extra.EncodeToBytes()
|
||||
assert.Nil(t, err)
|
||||
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)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, isEpochSwitchBlock, "header should be epoch switch", header)
|
||||
parentBlockInfo = &types.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
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{
|
||||
ProposedBlockInfo: parentBlockInfo,
|
||||
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{
|
||||
Round: types.Round(blockchain.Config().XDPoS.Epoch) + 2,
|
||||
|
|
@ -168,7 +168,7 @@ func TestAdaptorIsEpochSwitch(t *testing.T) {
|
|||
extraBytes, err = extra.EncodeToBytes()
|
||||
assert.Nil(t, err)
|
||||
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)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package engine_v2_tests
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -33,21 +34,23 @@ func TestIsAuthorisedMNForConsensusV2(t *testing.T) {
|
|||
func TestIsYourTurnConsensusV2(t *testing.T) {
|
||||
// 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)
|
||||
minePeriod := params.TestXDPoSV2Config.MinePeriod
|
||||
minePeriod := params.TestV2Configs[0].MinePeriod
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
blockNum := 901
|
||||
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)
|
||||
// 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.False(t, isYourTurn)
|
||||
|
||||
time.Sleep(time.Duration(minePeriod) * time.Second)
|
||||
// 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.True(t, isYourTurn)
|
||||
|
||||
|
|
@ -77,3 +80,30 @@ func TestIsYourTurnConsensusV2(t *testing.T) {
|
|||
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, uint64(913), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||
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, uint64(912), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||
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
|
||||
case <-time.After(5 * time.Second):
|
||||
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, uint64(914), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||
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, uint64(906), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||
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, uint64(1800), content.SmallerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||
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, uint64(1792), content.LargerRoundInfo.QuorumCert.ProposedBlockInfo.Number.Uint64())
|
||||
assert.Equal(t, 2, len(content.LargerRoundInfo.HashPath))
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ var (
|
|||
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
||||
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
acc4Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f292")
|
||||
acc5Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f293")
|
||||
voterKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
|
||||
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) //xdc703c4b2bD70c169f5717101CaeE543299Fc946C7
|
||||
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) //xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
|
||||
|
|
@ -310,10 +312,10 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
|||
for i := 1; i <= numOfBlocks; i++ {
|
||||
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
||||
// 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()
|
||||
}
|
||||
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)
|
||||
|
||||
err = blockchain.InsertBlock(block)
|
||||
|
|
@ -346,7 +348,7 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
|||
}
|
||||
|
||||
// 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
|
||||
checkpointBlockNumber := lastv1BlockNumber - lastv1BlockNumber%chainConfig.XDPoS.Epoch
|
||||
checkpointHeader := blockchain.GetHeaderByNumber(checkpointBlockNumber)
|
||||
|
|
@ -396,10 +398,10 @@ func PrepareXDCTestBlockChainWithPenaltyForV2Engine(t *testing.T, numOfBlocks in
|
|||
for i := 1; i <= numOfBlocks; i++ {
|
||||
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
||||
// 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()
|
||||
}
|
||||
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
|
||||
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()
|
||||
// use signer itself as penalty
|
||||
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"
|
||||
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)
|
||||
|
||||
header = &types.Header{
|
||||
|
|
@ -434,9 +436,9 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
|
|||
Coinbase: common.HexToAddress(blockCoinBase),
|
||||
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
|
||||
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.SwitchBlock.Uint64())
|
||||
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.FirstSwitchBlock.Uint64())
|
||||
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
|
||||
for _, v := range masternodesFromV1LastEpoch {
|
||||
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 {
|
||||
// epoch switch blocks, copy the master node list and inject into v2 validators
|
||||
// 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())
|
||||
for _, v := range masternodesFromV1LastEpoch {
|
||||
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)
|
||||
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
|
||||
header.Extra = []byte{}
|
||||
if len(header.Extra) < utils.ExtraVanity {
|
||||
|
|
@ -522,7 +524,7 @@ func createBlockFromHeader(bc *BlockChain, customHeader *types.Header, txs []*ty
|
|||
Difficulty: difficulty,
|
||||
Number: customHeader.Number,
|
||||
GasLimit: 1200000000,
|
||||
Time: big.NewInt(time.Now().Unix()),
|
||||
Time: big.NewInt(time.Now().Unix() - 1000000 + int64(customHeader.Number.Uint64()*10)),
|
||||
Extra: customHeader.Extra,
|
||||
Validator: customHeader.Validator,
|
||||
Validators: customHeader.Validators,
|
||||
|
|
@ -582,7 +584,7 @@ func findSignerAndSignFn(bc *BlockChain, header *types.Header, signer common.Add
|
|||
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 header.Number.Cmp(config.XDPoS.V2.SwitchBlock) > 0 {
|
||||
if header.Number.Cmp(config.XDPoS.V2.FirstSwitchBlock) > 0 {
|
||||
var decodedExtraField types.ExtraFields_v2
|
||||
err := utils.DecodeBytesExtraFields(header.Extra, &decodedExtraField)
|
||||
if err != nil {
|
||||
|
|
@ -659,7 +661,7 @@ func generateV2Extra(roundNumber int64, currentBlock *types.Block, signer common
|
|||
var signatures []types.Signature
|
||||
if len(accKeys) == 0 {
|
||||
// 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 {
|
||||
h := SignHashByPK(acc, types.VoteSigHash(voteForSign).Bytes())
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func TestInitialFirstV2Blcok(t *testing.T) {
|
|||
expectedQuorumCert := &types.QuorumCert{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
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, expectedQuorumCert, highQC)
|
||||
|
|
@ -43,10 +43,10 @@ func TestInitialFirstV2Blcok(t *testing.T) {
|
|||
assert.Equal(t, uint64(450), snap.Number)
|
||||
|
||||
// Test Running channels
|
||||
WaitPeriod := <-adaptor.WaitPeriodCh
|
||||
assert.Equal(t, params.TestXDPoSMockChainConfig.XDPoS.V2.WaitPeriod, WaitPeriod)
|
||||
waitPeriod := <-adaptor.WaitPeriodCh
|
||||
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
|
||||
assert.NotNil(t, timeoutMsg)
|
||||
assert.Equal(t, types.Round(1), timeoutMsg.(*types.Timeout).Round)
|
||||
|
|
@ -104,7 +104,7 @@ func TestInitialOtherV2Block(t *testing.T) {
|
|||
expectedQuorumCert := &types.QuorumCert{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
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, expectedQuorumCert, highQC)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import (
|
|||
func TestYourTurnInitialV2(t *testing.T) {
|
||||
config := params.TestXDPoSMockChainConfig
|
||||
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)
|
||||
|
||||
// Insert block 900
|
||||
|
|
@ -64,7 +64,7 @@ func TestShouldMineOncePerRound(t *testing.T) {
|
|||
config := params.TestXDPoSMockChainConfig
|
||||
blockchain, _, block910, signer, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, config, nil)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
minePeriod := config.XDPoS.V2.MinePeriod
|
||||
minePeriod := config.XDPoS.V2.CurrentConfig.MinePeriod
|
||||
|
||||
// Make sure we seal the parentBlock 910
|
||||
_, err := adaptor.Seal(blockchain, block910, nil)
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ func TestShouldNotSendVoteMessageIfAlreadyVoteForThisRound(t *testing.T) {
|
|||
select {
|
||||
case <-engineV2.BroadcastCh:
|
||||
t.Fatal("Should not trigger vote")
|
||||
case <-time.After(5 * time.Second):
|
||||
case <-time.After(3 * time.Second):
|
||||
// Shoud not trigger setNewRound
|
||||
round, _, _, _, highestVotedRound, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, types.Round(6), round)
|
||||
|
|
@ -290,7 +290,7 @@ func TestShouldNotSendVoteMsgIfBlockInfoRoundNotEqualCurrentRound(t *testing.T)
|
|||
select {
|
||||
case <-engineV2.BroadcastCh:
|
||||
t.Fatal("Should not trigger vote")
|
||||
case <-time.After(5 * time.Second):
|
||||
case <-time.After(3 * time.Second):
|
||||
// Shoud not trigger setNewRound
|
||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, types.Round(8), round)
|
||||
|
|
@ -334,7 +334,7 @@ func TestShouldNotSendVoteMsgIfBlockNotExtendedFromAncestor(t *testing.T) {
|
|||
select {
|
||||
case <-engineV2.BroadcastCh:
|
||||
t.Fatal("Should not trigger vote")
|
||||
case <-time.After(5 * time.Second):
|
||||
case <-time.After(3 * time.Second):
|
||||
// Shoud not trigger setNewRound
|
||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, types.Round(7), round)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ func TestHookRewardV2(t *testing.T) {
|
|||
err = json.Unmarshal([]byte(configString), &config)
|
||||
assert.Nil(t, err)
|
||||
// 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)
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ func TestHookRewardV2SplitReward(t *testing.T) {
|
|||
err = json.Unmarshal([]byte(configString), &config)
|
||||
assert.Nil(t, err)
|
||||
// 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)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package engine_v2_tests
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -41,11 +42,11 @@ func TestCountdownTimeoutNotToSendTimeoutMessageIfNotInMasternodeList(t *testing
|
|||
select {
|
||||
case <-engineV2.BroadcastCh:
|
||||
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)
|
||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||
engineV2.SetNewRoundFaker(blockchain, 1, true)
|
||||
|
|
@ -83,8 +84,63 @@ func TestSyncInfoAfterReachTimeoutSnycThreadhold(t *testing.T) {
|
|||
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
|
||||
func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
||||
params.TestXDPoSMockChainConfig.XDPoS.V2.CurrentConfig = params.TestV2Configs[0]
|
||||
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfig, nil)
|
||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ func TestShouldVerifyBlock(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
// Enable verify
|
||||
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
|
||||
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
|
@ -97,8 +95,9 @@ func TestShouldVerifyBlock(t *testing.T) {
|
|||
err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true)
|
||||
assert.Equal(t, consensus.ErrUnknownAncestor, err)
|
||||
|
||||
block901 := blockchain.GetBlockByNumber(901).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)
|
||||
assert.Equal(t, utils.ErrInvalidTimestamp, err)
|
||||
|
||||
|
|
@ -107,7 +106,7 @@ func TestShouldVerifyBlock(t *testing.T) {
|
|||
err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidDifficulty, err)
|
||||
|
||||
// Creat an invalid QC round
|
||||
// Create an invalid QC round
|
||||
proposedBlockInfo := &types.BlockInfo{
|
||||
Hash: blockchain.GetBlockByNumber(902).Hash(),
|
||||
Round: types.Round(2),
|
||||
|
|
@ -169,6 +168,62 @@ func TestShouldVerifyBlock(t *testing.T) {
|
|||
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) {
|
||||
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -179,8 +234,6 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
// Enable verify
|
||||
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
|
||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 902, &config, nil)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
|
@ -232,8 +285,6 @@ func TestShouldVerifyHeaders(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
// Enable verify
|
||||
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
|
||||
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
|
@ -273,8 +324,6 @@ func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
// Enable verify
|
||||
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
|
||||
blockchain, _, block910, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
|
@ -283,12 +332,12 @@ func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
|
|||
|
||||
// Create block 911 but don't write into DB
|
||||
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)
|
||||
|
||||
// Create block 912 and not write into DB as well
|
||||
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)
|
||||
|
||||
headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header())
|
||||
|
|
|
|||
|
|
@ -2541,7 +2541,7 @@ func (bc *BlockChain) UpdateM1() error {
|
|||
header := bc.CurrentHeader()
|
||||
var maxMasternodes int
|
||||
// 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
|
||||
maxMasternodes = common.MaxMasternodesV2
|
||||
} 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
|
||||
// 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{}
|
||||
if number.Uint64() > comebackHeight {
|
||||
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{})
|
||||
// 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
|
||||
}
|
||||
start := time.Now()
|
||||
|
|
@ -235,7 +235,7 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type
|
|||
if err != nil {
|
||||
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
|
||||
if epochCount == signEpochCount {
|
||||
endBlockNumber = header.Number.Uint64() - 1
|
||||
|
|
|
|||
|
|
@ -267,8 +267,7 @@ func (self *worker) update() {
|
|||
defer self.chainSideSub.Unsubscribe()
|
||||
|
||||
// timeout waiting for v1 inital value
|
||||
// TODO: Read value from config after we decide where is the config
|
||||
waitPeriod := 10
|
||||
waitPeriod := 2
|
||||
WaitPeriodCh := self.engine.(*XDPoS.XDPoS).WaitPeriodCh
|
||||
defer close(WaitPeriodCh)
|
||||
|
||||
|
|
|
|||
218
params/config.go
218
params/config.go
|
|
@ -26,6 +26,7 @@ import (
|
|||
const (
|
||||
ConsensusEngineVersion1 = "v1"
|
||||
ConsensusEngineVersion2 = "v2"
|
||||
Default = 0
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -36,30 +37,92 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
XDPoSV2Config = &V2{
|
||||
SwitchBlock: big.NewInt(9999999999),
|
||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||
TimeoutSyncThreshold: 3,
|
||||
TimeoutPeriod: 60,
|
||||
WaitPeriod: 10,
|
||||
MinePeriod: 10,
|
||||
MainnetV2Configs = map[uint64]*V2Config{
|
||||
Default: {
|
||||
SwitchBlock: big.NewInt(9999999999),
|
||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||
TimeoutSyncThreshold: 3,
|
||||
TimeoutPeriod: 60,
|
||||
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{
|
||||
SwitchBlock: big.NewInt(900),
|
||||
CertThreshold: 3,
|
||||
TimeoutSyncThreshold: 2,
|
||||
TimeoutPeriod: 10,
|
||||
WaitPeriod: 1,
|
||||
MinePeriod: 2,
|
||||
SkipV2Validation: true,
|
||||
TestV2Configs = map[uint64]*V2Config{
|
||||
Default: {
|
||||
SwitchBlock: big.NewInt(900),
|
||||
CertThreshold: 3,
|
||||
TimeoutSyncThreshold: 2,
|
||||
TimeoutPeriod: 4,
|
||||
WaitPeriod: 1,
|
||||
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),
|
||||
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
|
||||
TimeoutSyncThreshold: 5,
|
||||
TimeoutPeriod: 25,
|
||||
WaitPeriod: 10,
|
||||
MinePeriod: 10,
|
||||
|
||||
DevnetV2Configs = map[uint64]*V2Config{
|
||||
Default: {
|
||||
SwitchBlock: big.NewInt(7074000),
|
||||
CertThreshold: 4,
|
||||
TimeoutSyncThreshold: 5,
|
||||
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
|
||||
|
|
@ -78,7 +141,11 @@ var (
|
|||
RewardCheckpoint: 900,
|
||||
Gap: 450,
|
||||
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
|
||||
V2: XDPoSV2Config,
|
||||
V2: &V2{
|
||||
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
|
||||
CurrentConfig: MainnetV2Configs[0],
|
||||
AllConfigs: MainnetV2Configs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -116,11 +183,16 @@ var (
|
|||
RewardCheckpoint: 900,
|
||||
Gap: 450,
|
||||
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{
|
||||
ChainId: big.NewInt(551),
|
||||
HomesteadBlock: big.NewInt(1),
|
||||
|
|
@ -136,7 +208,11 @@ var (
|
|||
RewardCheckpoint: 900,
|
||||
Gap: 450,
|
||||
FoudationWalletAddr: common.HexToAddress("0x746249c61f5832c5eed53172776b460491bdcd5c"),
|
||||
V2: DevnetXDPoSV2Config,
|
||||
V2: &V2{
|
||||
FirstSwitchBlock: DevnetV2Configs[0].SwitchBlock,
|
||||
CurrentConfig: DevnetV2Configs[0],
|
||||
AllConfigs: DevnetV2Configs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +231,11 @@ var (
|
|||
XDPoS: &XDPoSConfig{
|
||||
Period: 15,
|
||||
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}
|
||||
|
||||
// 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}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
|
|
@ -242,28 +347,69 @@ type XDPoSConfig 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
|
||||
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
|
||||
SwitchBlock *big.Int `json:"switchBlock"` // v1 to v2 switch block number
|
||||
TimeoutSyncThreshold int `json:"timeoutSyncThreshold"` // send syncInfo after number of timeout
|
||||
TimeoutPeriod int `json:"timeoutPeriod"` // Duration in ms
|
||||
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.
|
||||
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 {
|
||||
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 {
|
||||
if c.V2 != nil && c.V2.SwitchBlock != nil && num.Cmp(c.V2.SwitchBlock) > 0 {
|
||||
if skipExtraCheck {
|
||||
return ConsensusEngineVersion2
|
||||
}
|
||||
if len(extraByte) == 0 || extraByte[0] != 2 {
|
||||
return ConsensusEngineVersion1
|
||||
}
|
||||
if !skipExtraCheck && (len(extraByte) == 0 || extraByte[0] != 2) {
|
||||
return ConsensusEngineVersion1
|
||||
}
|
||||
|
||||
if c.V2 != nil && c.V2.FirstSwitchBlock != nil && num.Cmp(c.V2.FirstSwitchBlock) > 0 {
|
||||
// We have to check each block configuration due to reorg chain case
|
||||
// Block may get rollback and old config need to apply to verify block
|
||||
c.updateV2Config(num.Uint64() - 1)
|
||||
return ConsensusEngineVersion2
|
||||
}
|
||||
return ConsensusEngineVersion1
|
||||
|
|
|
|||
Loading…
Reference in a new issue