Multi config bug fix (#216)

* refactor multi config
remove pool cleaner
correct message and log level
This commit is contained in:
Liam 2022-12-17 20:23:46 +08:00 committed by GitHub
parent 96339ec3ba
commit c4f9a552e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 319 additions and 200 deletions

View file

@ -346,7 +346,8 @@ func startNode(ctx *cli.Context, stack *node.Node, cfg XDCConfig) {
for range core.CheckpointCh {
log.Info("Checkpoint!!! It's time to reconcile node's state...")
log.Info("Update consensus parameters")
engine.UpdateParams()
chain := ethereum.BlockChain()
engine.UpdateParams(chain.CurrentHeader())
if common.IsTestnet {
ok, err = ethereum.ValidateMasternodeTestnet()
if err != nil {

View file

@ -37,8 +37,8 @@ import (
)
const (
ExtraFieldCheck = false
SkipExtraFieldCheck = true
ExtraFieldCheck = true
SkipExtraFieldCheck = false
)
func (x *XDPoS) SigHash(header *types.Header) (hash common.Hash) {
@ -79,7 +79,7 @@ func (x *XDPoS) SubscribeForensicsEvent(ch chan<- types.ForensicsEvent) event.Su
// New creates a XDPoS delegated-proof-of-stake consensus engine with the initial
// signers set to the ones provided by the user.
func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS {
log.Info("[New] initial conensus engines")
log.Info("[New] initialise consensus engines")
// Set any missing consensus parameters to their defaults
if config.Epoch == 0 {
config.Epoch = utils.EpochLength
@ -88,9 +88,9 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS {
// For testing and testing project, default to mainnet config
if config.V2 == nil {
config.V2 = &params.V2{
FirstSwitchBlock: params.MainnetV2Configs[0].SwitchBlock,
CurrentConfig: params.MainnetV2Configs[0],
AllConfigs: params.MainnetV2Configs,
SwitchBlock: params.XDCMainnetChainConfig.XDPoS.V2.SwitchBlock,
CurrentConfig: params.MainnetV2Configs[0],
AllConfigs: params.MainnetV2Configs,
}
}
@ -145,8 +145,14 @@ func NewFaker(db ethdb.Database, chainConfig *params.ChainConfig) *XDPoS {
}
// Reset parameters after checkpoint due to config may change
func (x *XDPoS) UpdateParams() {
x.EngineV2.UpdateParams()
func (x *XDPoS) UpdateParams(header *types.Header) {
switch x.config.BlockConsensusVersion(header.Number, header.Extra, ExtraFieldCheck) {
case params.ConsensusEngineVersion2:
x.EngineV2.UpdateParams(header)
return
default: // Default "v1"
return
}
}
func (x *XDPoS) Initial(chain consensus.ChainReader, header *types.Header) error {

View file

@ -116,7 +116,7 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *
timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout
engine.periodicJob()
config.BuildConfigIndex()
config.V2.BuildConfigIndex()
return engine
}
@ -131,7 +131,13 @@ signing. It is the hash of the entire header apart from the 65 byte signature
contained at the end of the extra data.
*/
func (x *XDPoS_v2) UpdateParams() {
func (x *XDPoS_v2) UpdateParams(header *types.Header) {
_, round, _, err := x.getExtraFields(header)
if err != nil {
log.Error("[UpdateParams] retrieve round failed", "block", header.Number.Uint64(), "err", err)
}
x.config.V2.UpdateConfig(uint64(round))
// Setup timeoutTimer
duration := time.Duration(x.config.V2.CurrentConfig.TimeoutPeriod) * time.Second
x.timeoutWorker.SetTimeoutDuration(duration)
@ -163,7 +169,7 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
var quorumCert *types.QuorumCert
var err error
if header.Number.Int64() == x.config.V2.FirstSwitchBlock.Int64() {
if header.Number.Int64() == x.config.V2.SwitchBlock.Int64() {
log.Info("[initial] highest QC for consensus v2 first block")
blockInfo := &types.BlockInfo{
Hash: header.Hash(),
@ -193,13 +199,13 @@ func (x *XDPoS_v2) initial(chain consensus.ChainReader, header *types.Header) er
}
// Initial first v2 snapshot
lastGapNum := x.config.V2.FirstSwitchBlock.Uint64() - x.config.Gap
lastGapNum := x.config.V2.SwitchBlock.Uint64() - x.config.Gap
lastGapHeader := chain.GetHeaderByNumber(lastGapNum)
snap, _ := loadSnapshot(x.db, lastGapHeader.Hash())
if snap == nil {
checkpointHeader := chain.GetHeaderByNumber(x.config.V2.FirstSwitchBlock.Uint64())
checkpointHeader := chain.GetHeaderByNumber(x.config.V2.SwitchBlock.Uint64())
log.Info("[initial] init first snapshot")
_, _, masternodes, err := x.getExtraFields(checkpointHeader)
@ -246,7 +252,9 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
}
waitedTime := time.Now().Unix() - parent.Time.Int64()
if waitedTime < int64(x.config.V2.CurrentConfig.MinePeriod) {
_, parentRound, _, err := x.getExtraFields(parent)
minePeriod := x.config.V2.Config(uint64(parentRound) + 1).MinePeriod // plus 1 means current block
if waitedTime < int64(minePeriod) {
log.Trace("[YourTurn] wait after mine period", "minePeriod", x.config.V2.CurrentConfig.MinePeriod, "waitedTime", waitedTime)
return false, nil
}
@ -718,7 +726,7 @@ func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, block
}
// Switch block is a v1 block, there is no valid extra to decode, nor its round
if blockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
if blockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 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")
@ -751,6 +759,12 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
4. Verify gapNumber = epochSwitchNumber - epochSwitchNumber%Epoch - Gap
5. Verify blockInfo
*/
if quorumCert == nil {
log.Warn("[verifyQC] QC is Nil")
return utils.ErrInvalidQC
}
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, parentHeader, quorumCert.ProposedBlockInfo.Hash)
if err != nil {
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
@ -763,13 +777,13 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
}
}
if quorumCert == nil {
log.Warn("[verifyQC] QC is Nil")
return utils.ErrInvalidQC
} else if (quorumCert.ProposedBlockInfo.Number.Uint64() > x.config.V2.FirstSwitchBlock.Uint64()) && (signatures == nil || (len(signatures) < x.config.V2.CurrentConfig.CertThreshold)) {
qcRound := quorumCert.ProposedBlockInfo.Round
certThreshold := x.config.V2.Config(uint64(qcRound)).CertThreshold
if (qcRound > 0) && (signatures == nil || (len(signatures) < 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
log.Warn("[verifyHeader] Invalid QC Signature is nil or less then config", "QC", quorumCert, "QCNumber", quorumCert.ProposedBlockInfo.Number, "Signatures len", len(signatures), "CertThreshold", certThreshold)
return utils.ErrInvalidQCSignatures
}
start := time.Now()
@ -798,7 +812,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
}
wg.Wait()
elapsed := time.Since(start)
log.Info("[verifyQC] time verify message signatures of qc", "elapsed", elapsed)
log.Debug("[verifyQC] time verify message signatures of qc", "elapsed", elapsed)
if haveError != nil {
return haveError
}
@ -826,7 +840,7 @@ func (x *XDPoS_v2) processQC(blockChainReader consensus.ChainReader, incomingQuo
log.Error("[processQC] Block not found using the QC", "quorumCert.ProposedBlockInfo.Hash", incomingQuorumCert.ProposedBlockInfo.Hash, "incomingQuorumCert.ProposedBlockInfo.Number", incomingQuorumCert.ProposedBlockInfo.Number)
return fmt.Errorf("block not found, number: %v, hash: %v", incomingQuorumCert.ProposedBlockInfo.Number, incomingQuorumCert.ProposedBlockInfo.Hash)
}
if proposedBlockHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) > 0 {
if proposedBlockHeader.Number.Cmp(x.config.V2.SwitchBlock) > 0 {
// Extra field contain parent information
proposedBlockQuorumCert, round, _, err := x.getExtraFields(proposedBlockHeader)
if err != nil {
@ -882,7 +896,7 @@ func (x *XDPoS_v2) getSyncInfo() *types.SyncInfo {
//Find parent and grandparent, check round number, if so, commit grandparent(grandGrandParent of currentBlock)
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.FirstSwitchBlock) <= 0 {
if big.NewInt(0).Sub(proposedBlockHeader.Number, big.NewInt(2)).Cmp(x.config.V2.SwitchBlock) <= 0 {
return false, nil
}
// Find the last two parent block and check their rounds are the continuous
@ -959,7 +973,7 @@ func (x *XDPoS_v2) calcMasternodes(chain consensus.ChainReader, blockNum *big.In
}
candidates := snap.NextEpochMasterNodes
if blockNum.Uint64() == x.config.V2.FirstSwitchBlock.Uint64()+1 {
if blockNum.Uint64() == x.config.V2.SwitchBlock.Uint64()+1 {
log.Info("[calcMasternodes] examing first v2 block")
return candidates, []common.Address{}, nil
}

View file

@ -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.FirstSwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
// if parent is last v1 block and this is first v2 block, this is treated as epoch switch
if parentHeader.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
if parentHeader.Number.Cmp(x.config.V2.SwitchBlock) == 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.FirstSwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch
return currentCheckpointNumber, epochNum, nil
}
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.FirstSwitchBlock) == 0 {
if header.Number.Cmp(x.config.V2.SwitchBlock) == 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.FirstSwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
// if parent is last v1 block and this is first v2 block, this is treated as epoch switch
if quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.FirstSwitchBlock) == 0 {
if quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
return true, epochNum, nil
}

View file

@ -28,15 +28,14 @@ func (x *XDPoS_v2) timeoutHandler(blockChainReader consensus.ChainReader, timeou
log.Debug("[timeoutHandler] collect timeout", "number", numberOfTimeoutsInPool)
// Threshold reached
isThresholdReached := numberOfTimeoutsInPool >= x.config.V2.CurrentConfig.CertThreshold
certThreshold := x.config.V2.Config(uint64(x.currentRound)).CertThreshold
isThresholdReached := numberOfTimeoutsInPool >= 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)
if err != nil {
return err
}
// clean up timeout message, regardless its GapNumber or round
x.timeoutPool.Clear()
}
return nil
}
@ -82,6 +81,11 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
- Use the above public key to find out the xdc address
- Use the above xdc address to check against the master node list from step 1(For the received TC epoch)
*/
if timeoutCert == nil || timeoutCert.Signatures == nil {
log.Warn("[verifyTC] TC or TC signatures is Nil")
return utils.ErrInvalidTC
}
snap, err := x.getSnapshot(chain, timeoutCert.GapNumber, true)
if err != nil {
log.Error("[verifyTC] Fail to get snapshot when verifying TC!", "TCGapNumber", timeoutCert.GapNumber)
@ -92,16 +96,21 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
return fmt.Errorf("Empty master node lists from snapshot")
}
if timeoutCert == nil {
log.Warn("[verifyTC] TC is Nil")
return utils.ErrInvalidTC
} 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
signatures, duplicates := UniqueSignatures(timeoutCert.Signatures)
if len(duplicates) != 0 {
for _, d := range duplicates {
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
}
}
certThreshold := x.config.V2.Config(uint64(timeoutCert.Round)).CertThreshold
if len(signatures) < certThreshold {
log.Warn("[verifyTC] Invalid TC Signature is nil or empty", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures), "CertThreshold", certThreshold)
return utils.ErrInvalidTCSignatures
}
var wg sync.WaitGroup
wg.Add(len(timeoutCert.Signatures))
wg.Add(len(signatures))
var haveError error
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
@ -109,17 +118,17 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
GapNumber: timeoutCert.GapNumber,
})
for _, signature := range timeoutCert.Signatures {
for _, signature := range signatures {
go func(sig types.Signature) {
defer wg.Done()
verified, _, err := x.verifyMsgSignature(signedTimeoutObj, sig, snap.NextEpochMasterNodes)
if err != nil {
log.Error("[verifyTC] Error while verfying TC message signatures", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures), "Error", err)
log.Error("[verifyTC] Error while verfying TC message signatures", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures), "Error", err)
haveError = fmt.Errorf("Error while verfying TC message signatures")
return
}
if !verified {
log.Warn("[verifyTC] Signature not verified doing TC verification", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures))
log.Warn("[verifyTC] Signature not verified doing TC verification", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures))
haveError = fmt.Errorf("Fail to verify TC due to signature mis-match")
return
}

View file

@ -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.FirstSwitchBlock) == 0 {
if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 {
masternodes = decodeMasternodesFromHeaderExtra(header)
return nil, types.Round(0), masternodes, nil
}

View file

@ -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.FirstSwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.CurrentConfig.MinePeriod) > header.Time.Uint64() {
if parent.Number.Uint64() > x.config.V2.SwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.CurrentConfig.MinePeriod) > header.Time.Uint64() {
return utils.ErrInvalidTimestamp
}

View file

@ -75,7 +75,8 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *types.Vote)
go x.ForensicsProcessor.DetectEquivocationInVotePool(voteMsg, x.votePool)
go x.ForensicsProcessor.ProcessVoteEquivocation(chain, x, voteMsg)
thresholdReached := numberOfVotesInPool >= x.config.V2.CurrentConfig.CertThreshold
certThreshold := x.config.V2.Config(uint64(voteMsg.ProposedBlockInfo.Round)).CertThreshold
thresholdReached := numberOfVotesInPool >= certThreshold
if thresholdReached {
log.Info(fmt.Sprintf("[voteHandler] Vote pool threashold reached: %v, number of items in the pool: %v", thresholdReached, numberOfVotesInPool))
@ -113,46 +114,48 @@ func (x *XDPoS_v2) onVotePoolThresholdReached(chain consensus.ChainReader, poole
// Filter out non-Master nodes signatures
var wg sync.WaitGroup
wg.Add(len(pooledVotes))
signatureSlice := make([]types.Signature, len(pooledVotes))
signatures := make([]types.Signature, len(pooledVotes))
counter := 0
for h, vote := range pooledVotes {
go func(hash common.Hash, v *types.Vote, i int) {
defer wg.Done()
verified, _, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
signedVote := types.VoteSigHash(&types.VoteForSign{
ProposedBlockInfo: v.ProposedBlockInfo,
GapNumber: v.GapNumber,
}), v.Signature, masternodes)
})
verified, _, err := x.verifyMsgSignature(signedVote, v.Signature, masternodes)
if err != nil {
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "Error", err.Error())
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "error", err.Error())
} else if !verified {
log.Warn("[onVotePoolThresholdReached] Skip not verified vote signatures when building QC", "verified", verified)
} else {
signatureSlice[i] = v.Signature
signatures[i] = v.Signature
}
}(h, vote.(*types.Vote), counter)
counter++
}
wg.Wait()
elapsed := time.Since(start)
log.Info("[onVotePoolThresholdReached] verify message signatures of vote pool took", "elapsed", elapsed)
log.Debug("[onVotePoolThresholdReached] verify message signatures of vote pool took", "elapsed", elapsed)
// The signature list may contain empty entey. we only care the ones with values
var validSignatureSlice []types.Signature
for _, v := range signatureSlice {
var validSignatures []types.Signature
for _, v := range signatures {
if len(v) != 0 {
validSignatureSlice = append(validSignatureSlice, v)
validSignatures = append(validSignatures, v)
}
}
// Skip and wait for the next vote to process again if valid votes is less than what we required
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))
certThreshold := x.config.V2.Config(uint64(currentVoteMsg.(*types.Vote).ProposedBlockInfo.Round)).CertThreshold
if len(validSignatures) < certThreshold {
log.Warn("[onVotePoolThresholdReached] Not enough valid signatures to generate QC", "VotesSignaturesAfterFilter", validSignatures, "NumberOfValidVotes", len(validSignatures), "NumberOfVotes", len(pooledVotes))
return nil
}
// Genrate QC
quorumCert := &types.QuorumCert{
ProposedBlockInfo: currentVoteMsg.(*types.Vote).ProposedBlockInfo,
Signatures: validSignatureSlice,
Signatures: validSignatures,
GapNumber: currentVoteMsg.(*types.Vote).GapNumber,
}
err := x.processQC(chain, quorumCert)

View file

@ -87,7 +87,9 @@ var (
ErrInvalidV2Extra = errors.New("Invalid v2 extra in the block")
ErrInvalidQC = errors.New("Invalid QC content")
ErrInvalidQCSignatures = errors.New("Invalid QC Signatures")
ErrInvalidTC = errors.New("Invalid TC content")
ErrInvalidTCSignatures = errors.New("Invalid TC Signatures")
ErrEmptyBlockInfoHash = errors.New("BlockInfo hash is empty")
ErrInvalidFieldInNonEpochSwitch = errors.New("Invalid field exist in a non-epoch swtich block")
ErrValidatorNotWithinMasternodes = errors.New("Validaotor address is not in the master node list")

View file

@ -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.FirstSwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
// reset extra
header.Extra = []byte{}
if len(header.Extra) < utils.ExtraVanity {

View file

@ -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.FirstSwitchBlock, big.NewInt(1))
headerV2.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, 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.FirstSwitchBlock),
Number: big.NewInt(0).Set(blockchain.Config().XDPoS.V2.SwitchBlock),
}
quorumCert := &types.QuorumCert{
ProposedBlockInfo: parentBlockInfo,
Signatures: nil,
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
}
extra := types.ExtraFields_v2{
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.FirstSwitchBlock, big.NewInt(1))
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, 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.FirstSwitchBlock, big.NewInt(1)),
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(1)),
}
quorumCert = &types.QuorumCert{
ProposedBlockInfo: parentBlockInfo,
Signatures: nil,
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
}
extra = types.ExtraFields_v2{
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.FirstSwitchBlock, big.NewInt(2))
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, 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.FirstSwitchBlock, big.NewInt(100)),
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(100)),
}
quorumCert = &types.QuorumCert{
ProposedBlockInfo: parentBlockInfo,
Signatures: nil,
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
}
extra = types.ExtraFields_v2{
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.FirstSwitchBlock, big.NewInt(101))
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, 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.FirstSwitchBlock, big.NewInt(100)),
Number: big.NewInt(0).Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(100)),
}
quorumCert = &types.QuorumCert{
ProposedBlockInfo: parentBlockInfo,
Signatures: nil,
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
}
extra = types.ExtraFields_v2{
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.FirstSwitchBlock, big.NewInt(101))
header.Number.Add(blockchain.Config().XDPoS.V2.SwitchBlock, big.NewInt(101))
isEpochSwitchBlock, _, err = adaptor.IsEpochSwitch(header)
assert.Nil(t, err)
assert.False(t, isEpochSwitchBlock, "header should not be epoch switch", header)

View file

@ -83,13 +83,13 @@ func TestIsYourTurnConsensusV2(t *testing.T) {
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)
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 909, params.TestXDPoSMockChainConfig, nil)
firstMinePeriod := blockchain.Config().XDPoS.V2.CurrentConfig.MinePeriod
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
blockNum := 911 // 911 is new config switch block
blockNum := 910 // 910 is new config switch block
blockCoinBase := "0x111000000000000000000000000000000123"
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 1, blockCoinBase, signer, signFn, nil, nil)
currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, blockNum, 10, blockCoinBase, signer, signFn, nil, nil)
currentBlockHeader := currentBlock.Header()
currentBlockHeader.Time = big.NewInt(time.Now().Unix())
err := blockchain.InsertBlock(currentBlock)
@ -100,8 +100,11 @@ func TestIsYourTurnConsensusV2CrossConfig(t *testing.T) {
assert.Nil(t, err)
assert.False(t, isYourTurn)
adaptor.UpdateParams(currentBlockHeader) // it will be triggered automatically on the real code by other process
// 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)

View file

@ -312,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.FirstSwitchBlock.Int64() {
if int64(i) > chainConfig.XDPoS.V2.SwitchBlock.Int64() {
blockCoinBase = signer.Hex()
}
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, nil, nil)
err = blockchain.InsertBlock(block)
@ -348,7 +348,7 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
}
// First v2 block
if (int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()) == 1 {
if (int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()) == 1 {
lastv1BlockNumber := block.Header().Number.Uint64() - 1
checkpointBlockNumber := lastv1BlockNumber - lastv1BlockNumber%chainConfig.XDPoS.Epoch
checkpointHeader := blockchain.GetHeaderByNumber(checkpointBlockNumber)
@ -398,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.FirstSwitchBlock.Int64() {
if int64(i) > chainConfig.XDPoS.V2.SwitchBlock.Int64() {
blockCoinBase = signer.Hex()
}
roundNumber := int64(i) - chainConfig.XDPoS.V2.FirstSwitchBlock.Int64()
roundNumber := int64(i) - chainConfig.XDPoS.V2.SwitchBlock.Int64()
// use signer itself as penalty
block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn, signer[:], nil)
@ -426,7 +426,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
var header *types.Header
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 1 { // Build engine v2 compatible extra data field
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 1 { // Build engine v2 compatible extra data field
extraInBytes := generateV2Extra(roundNumber, currentBlock, signer, signFn, signersKey)
header = &types.Header{
@ -436,9 +436,9 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
Coinbase: common.HexToAddress(blockCoinBase),
Extra: extraInBytes,
}
if int64(blockNumber) == (chainConfig.XDPoS.V2.FirstSwitchBlock.Int64() + 1) { // This is the first v2 block, we need to copy the last v1 epoch master node list and inject into v2 validators
if int64(blockNumber) == (chainConfig.XDPoS.V2.SwitchBlock.Int64() + 1) { // This is the first v2 block, we need to copy the last v1 epoch master node list and inject into v2 validators
// Get last master node list from last v1 block
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.FirstSwitchBlock.Uint64())
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.SwitchBlock.Uint64())
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
for _, v := range masternodesFromV1LastEpoch {
header.Validators = append(header.Validators, v[:]...)
@ -446,7 +446,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
} else if roundNumber%int64(chainConfig.XDPoS.Epoch) == 0 {
// 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.FirstSwitchBlock.Uint64())
lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.V2.SwitchBlock.Uint64())
masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header())
for _, v := range masternodesFromV1LastEpoch {
header.Validators = append(header.Validators, v[:]...)
@ -465,7 +465,7 @@ func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, starti
}
// Inject the hardcoded master node list for the last v1 epoch block and all v1 epoch switch blocks (excluding genesis)
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.FirstSwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.V2.SwitchBlock) == 0 || blockNumber%int(chainConfig.XDPoS.Epoch) == 0 {
// reset extra
header.Extra = []byte{}
if len(header.Extra) < utils.ExtraVanity {
@ -584,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.FirstSwitchBlock) > 0 {
if header.Number.Cmp(config.XDPoS.V2.SwitchBlock) > 0 {
var decodedExtraField types.ExtraFields_v2
err := utils.DecodeBytesExtraFields(header.Extra, &decodedExtraField)
if err != nil {

View file

@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/assert"
)
func TestInitialFirstV2Blcok(t *testing.T) {
func TestInitialFirstV2Block(t *testing.T) {
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 900, params.TestXDPoSMockChainConfig, nil)
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
header := currentBlock.Header()
@ -32,7 +32,7 @@ func TestInitialFirstV2Blcok(t *testing.T) {
expectedQuorumCert := &types.QuorumCert{
ProposedBlockInfo: blockInfo,
Signatures: nil,
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
}
assert.Equal(t, types.Round(1), round)
assert.Equal(t, expectedQuorumCert, highQC)
@ -104,7 +104,7 @@ func TestInitialOtherV2Block(t *testing.T) {
expectedQuorumCert := &types.QuorumCert{
ProposedBlockInfo: blockInfo,
Signatures: []types.Signature{},
GapNumber: blockchain.Config().XDPoS.V2.FirstSwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
GapNumber: blockchain.Config().XDPoS.V2.SwitchBlock.Uint64() - blockchain.Config().XDPoS.Gap,
}
assert.Equal(t, types.Round(11), round)
assert.Equal(t, expectedQuorumCert, highQC)

View file

@ -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.FirstSwitchBlock.SetUint64(1800)
config.XDPoS.V2.SwitchBlock.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.FirstSwitchBlock.SetUint64(1800)
config.XDPoS.V2.SwitchBlock.SetUint64(1800)
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch)*3, &config, nil)

View file

@ -115,7 +115,7 @@ func TestTimeoutPeriodAndThreadholdConfigChange(t *testing.T) {
err := blockchain.InsertBlock(currentBlock)
assert.Nil(t, err)
engineV2.UpdateParams() // it will be triggered automatically on the real code by other process
engineV2.UpdateParams(currentBlockHeader) // it will be triggered automatically on the real code by other process
t.Log("waiting for another consecutive period")
// another consecutive period

View file

@ -183,7 +183,7 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
// Genrate QC
// Genrate 911 QC
proposedBlockInfo := &types.BlockInfo{
Hash: blockchain.GetBlockByNumber(911).Hash(),
Round: types.Round(11),
@ -198,11 +198,11 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
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)
var signaturesFirst []types.Signature
signaturesFirst = append(signaturesFirst, acc1SignedHash, acc2SignedHash, acc3SignedHash)
quorumCert := &types.QuorumCert{
ProposedBlockInfo: proposedBlockInfo,
Signatures: signatures,
Signatures: signaturesFirst,
GapNumber: 450,
}
@ -210,18 +210,53 @@ func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
Round: types.Round(12),
QuorumCert: quorumCert,
}
extraInBytes, err := extra.EncodeToBytes()
if err != nil {
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
}
extraInBytes, _ := extra.EncodeToBytes()
// 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)
assert.Equal(t, utils.ErrInvalidQCSignatures, err)
// Make we verification process use the corresponding config
// Genrate 910 QC
proposedBlockInfo = &types.BlockInfo{
Hash: blockchain.GetBlockByNumber(910).Hash(),
Round: types.Round(10),
Number: blockchain.GetBlockByNumber(910).Number(),
}
voteForSign = &types.VoteForSign{
ProposedBlockInfo: proposedBlockInfo,
GapNumber: 450,
}
// Sign from acc 1, 2, 3
acc1SignedHash = SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
acc2SignedHash = SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
acc3SignedHash = SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
var signaturesThr []types.Signature
signaturesThr = append(signaturesThr, acc1SignedHash, acc2SignedHash, acc3SignedHash)
quorumCert = &types.QuorumCert{
ProposedBlockInfo: proposedBlockInfo,
Signatures: signaturesThr,
GapNumber: 450,
}
extra = types.ExtraFields_v2{
Round: types.Round(11),
QuorumCert: quorumCert,
}
extraInBytes, _ = extra.EncodeToBytes()
// QC contains 910, so it requires 3 signatures, not use block number to determine which config to use
block911 := blockchain.GetBlockByNumber(911).Header()
block911.Extra = extraInBytes
err = adaptor.VerifyHeader(blockchain, block911, true)
// error ErrValidatorNotWithinMasternodes means verifyQC is passed and move to next verification process
assert.Equal(t, utils.ErrValidatorNotWithinMasternodes, err)
}
func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
@ -271,7 +306,7 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
headerWithDuplicatedSignatures.Extra = extraInBytes
// Happy path
err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true)
assert.Equal(t, utils.ErrInvalidQC, err)
assert.Equal(t, utils.ErrInvalidQCSignatures, err)
}
@ -332,12 +367,12 @@ func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
// Create block 911 but don't write into DB
blockNumber := 911
roundNumber := int64(blockNumber) - config.XDPoS.V2.FirstSwitchBlock.Int64()
roundNumber := int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
block911 := CreateBlock(blockchain, &config, block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil)
// Create block 912 and not write into DB as well
blockNumber = 912
roundNumber = int64(blockNumber) - config.XDPoS.V2.FirstSwitchBlock.Int64()
roundNumber = int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
block912 := CreateBlock(blockchain, &config, block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil)
headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header())

View file

@ -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.FirstSwitchBlock != nil && header.Number.Cmp(bc.chainConfig.XDPoS.V2.FirstSwitchBlock) == 1) {
if bc.chainConfig.IsTIPIncreaseMasternodes(header.Number) || (bc.chainConfig.XDPoS.V2.SwitchBlock != nil && header.Number.Cmp(bc.chainConfig.XDPoS.V2.SwitchBlock) == 1) {
// using new masterndoes
maxMasternodes = common.MaxMasternodesV2
} else {

View file

@ -321,7 +321,6 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
// DefaultGenesisBlock returns the Ethereum main net genesis block.
func DefaultGenesisBlock() *Genesis {
config := params.XDCMainnetChainConfig
config.XDPoS.V2 = nil
return &Genesis{
Config: config,
Nonce: 0,

View file

@ -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.FirstSwitchBlock.Uint64()
comebackHeight := (common.LimitPenaltyEpochV2+1)*chain.Config().XDPoS.Epoch + chain.Config().XDPoS.V2.SwitchBlock.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.FirstSwitchBlock.Uint64()+1 {
if number == chain.Config().XDPoS.V2.SwitchBlock.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.FirstSwitchBlock.Uint64()+1 {
if isEpochSwitch && i != chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
epochCount += 1
if epochCount == signEpochCount {
endBlockNumber = header.Number.Uint64() - 1

View file

@ -291,7 +291,7 @@ func (self *worker) update() {
// A real event arrived, process interesting content
select {
case v := <-WaitPeriodCh:
log.Info("[worker] update mine period", "period", v)
log.Info("[worker] update wait period", "period", v)
waitPeriod = v
timeout.Reset(time.Duration(waitPeriod) * time.Second)

View file

@ -19,8 +19,10 @@ package params
import (
"fmt"
"math/big"
"sync"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/log"
)
const (
@ -39,7 +41,7 @@ var (
var (
MainnetV2Configs = map[uint64]*V2Config{
Default: {
SwitchBlock: big.NewInt(9999999999),
SwitchRound: 0,
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 60,
@ -47,7 +49,7 @@ var (
MinePeriod: 10,
},
9999999999: {
SwitchBlock: big.NewInt(9999999999),
SwitchRound: 9999999999,
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
TimeoutSyncThreshold: 3,
TimeoutPeriod: 60,
@ -57,31 +59,23 @@ var (
}
TestV2Configs = map[uint64]*V2Config{
Default: {
SwitchBlock: big.NewInt(900),
SwitchRound: 0,
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),
10: {
SwitchRound: 10,
CertThreshold: 5,
TimeoutSyncThreshold: 2,
TimeoutPeriod: 4,
WaitPeriod: 2,
MinePeriod: 3,
},
1799: {
SwitchBlock: big.NewInt(1799),
899: {
SwitchRound: 899,
CertThreshold: 5,
TimeoutSyncThreshold: 4,
TimeoutPeriod: 5,
@ -92,31 +86,23 @@ var (
DevnetV2Configs = map[uint64]*V2Config{
Default: {
SwitchBlock: big.NewInt(7074000),
CertThreshold: 4,
TimeoutSyncThreshold: 5,
TimeoutPeriod: 10,
WaitPeriod: 5,
MinePeriod: 5,
},
7074000: {
SwitchBlock: big.NewInt(7074000),
SwitchRound: 0,
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
TimeoutSyncThreshold: 5,
TimeoutPeriod: 25,
WaitPeriod: 10,
MinePeriod: 10,
},
7224300: {
SwitchBlock: big.NewInt(7224300),
151919: {
SwitchRound: 151919,
CertThreshold: common.MaxMasternodesV2*1/2 + 1,
TimeoutSyncThreshold: 8,
TimeoutPeriod: 50,
WaitPeriod: 5,
MinePeriod: 20,
},
7242300: {
SwitchBlock: big.NewInt(7242300),
171000: {
SwitchRound: 171000,
CertThreshold: common.MaxMasternodesV2*2/3 + 1,
TimeoutSyncThreshold: 5,
TimeoutPeriod: 25,
@ -142,9 +128,9 @@ var (
Gap: 450,
FoudationWalletAddr: common.HexToAddress("xdc92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"),
V2: &V2{
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
CurrentConfig: MainnetV2Configs[0],
AllConfigs: MainnetV2Configs,
SwitchBlock: big.NewInt(9999999999),
CurrentConfig: MainnetV2Configs[0],
AllConfigs: MainnetV2Configs,
},
},
}
@ -184,7 +170,7 @@ var (
Gap: 450,
FoudationWalletAddr: common.HexToAddress("xdc746249c61f5832c5eed53172776b460491bdcd5c"),
V2: &V2{
FirstSwitchBlock: TestV2Configs[0].SwitchBlock,
SwitchBlock: big.NewInt(900),
CurrentConfig: TestV2Configs[0],
AllConfigs: TestV2Configs,
SkipV2Validation: true,
@ -209,9 +195,9 @@ var (
Gap: 450,
FoudationWalletAddr: common.HexToAddress("0x746249c61f5832c5eed53172776b460491bdcd5c"),
V2: &V2{
FirstSwitchBlock: DevnetV2Configs[0].SwitchBlock,
CurrentConfig: DevnetV2Configs[0],
AllConfigs: DevnetV2Configs,
SwitchBlock: big.NewInt(7074000),
CurrentConfig: DevnetV2Configs[0],
AllConfigs: DevnetV2Configs,
},
},
}
@ -232,9 +218,9 @@ var (
Period: 15,
Epoch: 30000,
V2: &V2{
FirstSwitchBlock: MainnetV2Configs[0].SwitchBlock,
CurrentConfig: MainnetV2Configs[0],
AllConfigs: MainnetV2Configs,
SwitchBlock: big.NewInt(9999999999),
CurrentConfig: MainnetV2Configs[0],
AllConfigs: MainnetV2Configs,
},
},
}
@ -275,9 +261,9 @@ var (
FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"),
Reward: 250,
V2: &V2{
FirstSwitchBlock: TestV2Configs[0].SwitchBlock,
CurrentConfig: TestV2Configs[0],
AllConfigs: TestV2Configs,
SwitchBlock: big.NewInt(900),
CurrentConfig: TestV2Configs[0],
AllConfigs: TestV2Configs,
},
},
}
@ -347,27 +333,78 @@ 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
lock sync.RWMutex // Protects the signer fields
SwitchBlock *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
SwitchRound uint64 `json:"switchRound"` // v1 to v2 switch block number
WaitPeriod int `json:"waitPeriod"` // Miner wait period to check mine event
MinePeriod int `json:"minePeriod"` // Miner mine period to mine a block
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
}
// String implements the stringer interface, returning the consensus engine details.
func (c *XDPoSConfig) BuildConfigIndex() {
func (c *XDPoSConfig) String() string {
return "XDPoS"
}
func (c *XDPoSConfig) BlockConsensusVersion(num *big.Int, extraByte []byte, extraCheck bool) string {
if extraCheck && (len(extraByte) == 0 || extraByte[0] != 2) {
return ConsensusEngineVersion1
}
if c.V2 != nil && c.V2.SwitchBlock != nil && num.Cmp(c.V2.SwitchBlock) > 0 {
return ConsensusEngineVersion2
}
return ConsensusEngineVersion1
}
func (v *V2) UpdateConfig(round uint64) {
v.lock.Lock()
defer v.lock.Unlock()
var index uint64
//find the right config
for i := range v.configIndex {
if v.configIndex[i] <= round {
index = v.configIndex[i]
} else {
break
}
}
// update to current config
log.Info("[updateV2Config] Update config", "index", index, "round", round, "SwitchRound", v.AllConfigs[index].SwitchRound)
v.CurrentConfig = v.AllConfigs[index]
}
func (v *V2) Config(round uint64) *V2Config {
configRound := round - 1 //start from next block from SwitchRound number
var index uint64
//find the right config
for i := range v.configIndex {
if v.configIndex[i] <= configRound {
index = v.configIndex[i]
} else {
break
}
}
return v.AllConfigs[index]
}
func (v *V2) BuildConfigIndex() {
var list []uint64
for i := range c.V2.AllConfigs {
for i := range v.AllConfigs {
list = append(list, i)
}
@ -379,40 +416,12 @@ func (c *XDPoSConfig) BuildConfigIndex() {
}
}
}
c.V2.configIndex = list
log.Info("[BuildConfigIndex] config list", "list", list)
v.configIndex = list
}
func (c *XDPoSConfig) String() string {
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 !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
func (v *V2) ConfigIndex() []uint64 {
return v.configIndex
}
// String implements the fmt.Stringer interface.

View file

@ -20,6 +20,8 @@ import (
"math/big"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCheckCompatible(t *testing.T) {
@ -79,3 +81,39 @@ func TestCheckCompatible(t *testing.T) {
}
}
}
func TestUpdateV2Config(t *testing.T) {
TestnetChainConfig.XDPoS.V2.BuildConfigIndex()
c := TestnetChainConfig.XDPoS.V2.CurrentConfig
assert.Equal(t, 3, c.CertThreshold)
TestnetChainConfig.XDPoS.V2.UpdateConfig(10)
c = TestnetChainConfig.XDPoS.V2.CurrentConfig
assert.Equal(t, 5, c.CertThreshold)
TestnetChainConfig.XDPoS.V2.UpdateConfig(899)
c = TestnetChainConfig.XDPoS.V2.CurrentConfig
assert.Equal(t, 4, c.TimeoutSyncThreshold)
}
func TestV2Config(t *testing.T) {
TestnetChainConfig.XDPoS.V2.BuildConfigIndex()
c := TestnetChainConfig.XDPoS.V2.Config(1)
assert.Equal(t, 3, c.CertThreshold)
c = TestnetChainConfig.XDPoS.V2.Config(5)
assert.Equal(t, 3, c.CertThreshold)
c = TestnetChainConfig.XDPoS.V2.Config(10)
assert.Equal(t, 3, c.CertThreshold)
c = TestnetChainConfig.XDPoS.V2.Config(11)
assert.Equal(t, 5, c.CertThreshold)
}
func TestBuildConfigIndex(t *testing.T) {
TestnetChainConfig.XDPoS.V2.BuildConfigIndex()
index := TestnetChainConfig.XDPoS.V2.ConfigIndex()
expected := []uint64{0, 10, 899}
assert.Equal(t, expected, index)
}