mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
XIN-159, 160 and 161 (#69)
* XIN-159, 160 and 161 * update the bft handler to make sure we don't process dis-qualified messages * add verify header missing checks and its tests
This commit is contained in:
parent
a4b362ae9a
commit
9bb1a6e1b3
14 changed files with 547 additions and 233 deletions
|
|
@ -590,10 +590,13 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
|||
|
||||
// Verify this is truely a v2 block first
|
||||
|
||||
quorumCert, _, _, err := x.getExtraFields(header)
|
||||
quorumCert, round, _, err := x.getExtraFields(header)
|
||||
if err != nil {
|
||||
return utils.ErrInvalidV2Extra
|
||||
}
|
||||
if round <= quorumCert.ProposedBlockInfo.Round {
|
||||
return utils.ErrRoundInvalid
|
||||
}
|
||||
|
||||
err = x.verifyQC(chain, quorumCert)
|
||||
if err != nil {
|
||||
|
|
@ -613,6 +616,10 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
|||
return utils.ErrInvalidUncleHash
|
||||
}
|
||||
|
||||
if header.Difficulty.Cmp(big.NewInt(1)) != 0 {
|
||||
return utils.ErrInvalidDifficulty
|
||||
}
|
||||
|
||||
isEpochSwitch, _, err := x.IsEpochSwitch(header) // Verify v2 block that is on the epoch switch
|
||||
if err != nil {
|
||||
log.Error("[verifyHeader] error when checking if header is epoch switch header", "Hash", header.Hash(), "Number", header.Number, "Error", err)
|
||||
|
|
@ -628,6 +635,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
|||
if len(header.Validators)%common.AddressLength != 0 {
|
||||
return utils.ErrInvalidCheckpointSigners
|
||||
}
|
||||
// TODO: Add checkMasternodesOnEpochSwitch
|
||||
} else {
|
||||
if len(header.Validators) != 0 {
|
||||
log.Warn("[verifyHeader] Validators shall not have values in non-epochSwitch block", "Hash", header.Hash(), "Number", header.Number, "Validators", header.Validators)
|
||||
|
|
@ -652,47 +660,54 @@ 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.Time.Uint64()+uint64(x.config.V2.MinePeriod) > header.Time.Uint64() {
|
||||
if parent.Number.Uint64() > x.config.V2.SwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.MinePeriod) > header.Time.Uint64() {
|
||||
return utils.ErrInvalidTimestamp
|
||||
}
|
||||
// TODO: verifySeal XIN-135
|
||||
// TODO: item 9. check validator
|
||||
|
||||
_, penalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash)
|
||||
if err != nil {
|
||||
log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash())
|
||||
return err
|
||||
}
|
||||
|
||||
if !utils.CompareSignersLists(common.ExtractAddressFromBytes(header.Penalties), penalties) {
|
||||
return utils.ErrPenaltyListDoesNotMatch
|
||||
}
|
||||
|
||||
x.verifiedHeaders.Add(header.Hash(), true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Utils for test to get current Pool size
|
||||
func (x *XDPoS_v2) GetVotePoolSize(vote *utils.Vote) int {
|
||||
return x.votePool.Size(vote)
|
||||
}
|
||||
|
||||
// Utils for test to get Timeout Pool Size
|
||||
func (x *XDPoS_v2) GetTimeoutPoolSize(timeout *utils.Timeout) int {
|
||||
return x.timeoutPool.Size(timeout)
|
||||
}
|
||||
|
||||
/*
|
||||
SyncInfo workflow
|
||||
*/
|
||||
// Verify syncInfo and trigger process QC or TC if successful
|
||||
func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *utils.SyncInfo) error {
|
||||
func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *utils.SyncInfo) (bool, error) {
|
||||
/*
|
||||
1. Verify items including:
|
||||
1. Check QC and TC against highest QC TC. Skip if none of them need to be updated
|
||||
2. Verify items including:
|
||||
- verifyQC
|
||||
- verifyTC
|
||||
2. Broadcast(Not part of consensus)
|
||||
3. Broadcast(Not part of consensus)
|
||||
*/
|
||||
|
||||
if (x.highestQuorumCert.ProposedBlockInfo.Round >= syncInfo.HighestQuorumCert.ProposedBlockInfo.Round) && (x.highestTimeoutCert.Round >= syncInfo.HighestTimeoutCert.Round) {
|
||||
log.Warn("[VerifySyncInfoMessage] Round from incoming syncInfo message is no longer qualified", "Highest QC Round", x.highestQuorumCert.ProposedBlockInfo.Round, "Incoming SyncInfo QC Round", syncInfo.HighestQuorumCert.ProposedBlockInfo.Round, "highestTimeoutCert Round", x.highestTimeoutCert.Round, "Incoming syncInfo TC Round", syncInfo.HighestTimeoutCert.Round)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err := x.verifyQC(chain, syncInfo.HighestQuorumCert)
|
||||
if err != nil {
|
||||
log.Warn("SyncInfo message verification failed due to QC", err)
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
err = x.verifyTC(chain, syncInfo.HighestTimeoutCert)
|
||||
if err != nil {
|
||||
log.Warn("SyncInfo message verification failed due to TC", err)
|
||||
return err
|
||||
return false, err
|
||||
}
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (x *XDPoS_v2) SyncInfoHandler(chain consensus.ChainReader, syncInfo *utils.SyncInfo) error {
|
||||
|
|
@ -714,17 +729,19 @@ func (x *XDPoS_v2) SyncInfoHandler(chain consensus.ChainReader, syncInfo *utils.
|
|||
*/
|
||||
func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *utils.Vote) (bool, error) {
|
||||
/*
|
||||
1. Get masterNode list from snapshot
|
||||
2. Check signature:
|
||||
1. Check vote round with current round for fast fail(disqualifed)
|
||||
2. Get masterNode list from snapshot
|
||||
3. Check signature:
|
||||
- Use ecRecover to get the public key
|
||||
- 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 running epoch)
|
||||
4. Broadcast(Not part of consensus)
|
||||
*/
|
||||
err := x.VerifyBlockInfo(chain, vote.ProposedBlockInfo)
|
||||
if err != nil {
|
||||
return false, err
|
||||
if vote.ProposedBlockInfo.Round < x.currentRound {
|
||||
log.Warn("[VerifyVoteMessage] Disqualified vote message as the proposed round does not match currentRound", "vote.ProposedBlockInfo.Round", vote.ProposedBlockInfo.Round, "currentRound", x.currentRound)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
snapshot, err := x.getSnapshot(chain, vote.ProposedBlockInfo.Number.Uint64(), false)
|
||||
if err != nil {
|
||||
log.Error("[VerifyVoteMessage] fail to get snapshot for a vote message", "BlockNum", vote.ProposedBlockInfo.Number, "Hash", vote.ProposedBlockInfo.Hash, "Error", err.Error())
|
||||
|
|
@ -770,7 +787,13 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote)
|
|||
return nil
|
||||
}
|
||||
|
||||
err := x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg, proposedBlockHeader)
|
||||
err := x.VerifyBlockInfo(chain, voteMsg.ProposedBlockInfo)
|
||||
if err != nil {
|
||||
x.votePool.ClearPoolKeyByObj(voteMsg)
|
||||
return err
|
||||
}
|
||||
|
||||
err = x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg, proposedBlockHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1487,41 +1510,6 @@ func (x *XDPoS_v2) isExtendingFromAncestor(blockChainReader consensus.ChainReade
|
|||
return false, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Testing tools
|
||||
*/
|
||||
|
||||
func (x *XDPoS_v2) SetNewRoundFaker(blockChainReader consensus.ChainReader, newRound utils.Round, resetTimer bool) {
|
||||
x.lock.Lock()
|
||||
defer x.lock.Unlock()
|
||||
// Reset a bunch of things
|
||||
if resetTimer {
|
||||
x.timeoutWorker.Reset(blockChainReader)
|
||||
}
|
||||
x.currentRound = newRound
|
||||
}
|
||||
|
||||
// for test only
|
||||
func (x *XDPoS_v2) ProcessQC(chain consensus.ChainReader, qc *utils.QuorumCert) error {
|
||||
x.lock.Lock()
|
||||
defer x.lock.Unlock()
|
||||
return x.processQC(chain, qc)
|
||||
}
|
||||
|
||||
// Utils for test to check currentRound value
|
||||
func (x *XDPoS_v2) GetCurrentRound() utils.Round {
|
||||
x.lock.RLock()
|
||||
defer x.lock.RUnlock()
|
||||
return x.currentRound
|
||||
}
|
||||
|
||||
// Utils for test to check currentRound value
|
||||
func (x *XDPoS_v2) GetProperties() (utils.Round, *utils.QuorumCert, *utils.QuorumCert, utils.Round, *utils.BlockInfo) {
|
||||
x.lock.RLock()
|
||||
defer x.lock.RUnlock()
|
||||
return x.currentRound, x.lockQuorumCert, x.highestQuorumCert, x.highestVotedRound, x.highestCommitBlock
|
||||
}
|
||||
|
||||
// Get master nodes over extra data of epoch switch block.
|
||||
func (x *XDPoS_v2) GetMasternodesFromEpochSwitchHeader(epochSwitchHeader *types.Header) []common.Address {
|
||||
if epochSwitchHeader == nil {
|
||||
|
|
@ -1539,7 +1527,7 @@ func (x *XDPoS_v2) GetMasternodesFromEpochSwitchHeader(epochSwitchHeader *types.
|
|||
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 {
|
||||
log.Info("[IsEpochSwitch] examing last v1 block 👯♂️")
|
||||
log.Info("[IsEpochSwitch] examing last v1 block")
|
||||
return true, header.Number.Uint64() / x.config.Epoch, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
59
consensus/XDPoS/engines/engine_v2/testing_utils.go
Normal file
59
consensus/XDPoS/engines/engine_v2/testing_utils.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package engine_v2
|
||||
|
||||
import (
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
Testing tools
|
||||
*/
|
||||
|
||||
func (x *XDPoS_v2) SetNewRoundFaker(blockChainReader consensus.ChainReader, newRound utils.Round, resetTimer bool) {
|
||||
x.lock.Lock()
|
||||
defer x.lock.Unlock()
|
||||
// Reset a bunch of things
|
||||
if resetTimer {
|
||||
x.timeoutWorker.Reset(blockChainReader)
|
||||
}
|
||||
x.currentRound = newRound
|
||||
}
|
||||
|
||||
// for test only
|
||||
func (x *XDPoS_v2) ProcessQCFaker(chain consensus.ChainReader, qc *utils.QuorumCert) error {
|
||||
x.lock.Lock()
|
||||
defer x.lock.Unlock()
|
||||
return x.processQC(chain, qc)
|
||||
}
|
||||
|
||||
// Utils for test to check currentRound value
|
||||
func (x *XDPoS_v2) GetCurrentRoundFaker() utils.Round {
|
||||
x.lock.RLock()
|
||||
defer x.lock.RUnlock()
|
||||
return x.currentRound
|
||||
}
|
||||
|
||||
// Utils for test to get current Pool size
|
||||
func (x *XDPoS_v2) GetVotePoolSizeFaker(vote *utils.Vote) int {
|
||||
return x.votePool.Size(vote)
|
||||
}
|
||||
|
||||
// Utils for test to get Timeout Pool Size
|
||||
func (x *XDPoS_v2) GetTimeoutPoolSizeFaker(timeout *utils.Timeout) int {
|
||||
return x.timeoutPool.Size(timeout)
|
||||
}
|
||||
|
||||
// WARN: This function is designed for testing purpose only!
|
||||
// Utils for test to check currentRound values
|
||||
func (x *XDPoS_v2) GetPropertiesFaker() (utils.Round, *utils.QuorumCert, *utils.QuorumCert, *utils.TimeoutCert, utils.Round, *utils.BlockInfo) {
|
||||
x.lock.RLock()
|
||||
defer x.lock.RUnlock()
|
||||
return x.currentRound, x.lockQuorumCert, x.highestQuorumCert, x.highestTimeoutCert, x.highestVotedRound, x.highestCommitBlock
|
||||
}
|
||||
|
||||
// WARN: This function is designed for testing purpose only!
|
||||
// Utils for tests to set engine specific values
|
||||
func (x *XDPoS_v2) SetPropertiesFaker(highestQC *utils.QuorumCert, highestTC *utils.TimeoutCert) {
|
||||
x.highestQuorumCert = highestQC
|
||||
x.highestTimeoutCert = highestTC
|
||||
}
|
||||
|
|
@ -85,6 +85,9 @@ var (
|
|||
ErrInvalidTC = errors.New("Invalid TC content")
|
||||
ErrEmptyBlockInfoHash = errors.New("BlockInfo hash is empty")
|
||||
ErrInvalidFieldInNonEpochSwitch = errors.New("Invalid field exist in a non-epoch swtich block")
|
||||
|
||||
ErrPenaltyListDoesNotMatch = errors.New("Incoming block penalty list does not match")
|
||||
ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round")
|
||||
)
|
||||
|
||||
type ErrIncomingMessageRoundNotEqualCurrentRound struct {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func TestInitialFirstV2Blcok(t *testing.T) {
|
|||
err := adaptor.EngineV2.Initial(blockchain, header)
|
||||
assert.Nil(t, err)
|
||||
|
||||
round, _, highQC, _, _ := adaptor.EngineV2.GetProperties()
|
||||
round, _, highQC, _, _, _ := adaptor.EngineV2.GetPropertiesFaker()
|
||||
blockInfo := &utils.BlockInfo{
|
||||
Hash: header.Hash(),
|
||||
Round: utils.Round(0),
|
||||
|
|
@ -98,7 +98,7 @@ func TestInitialOtherV2Block(t *testing.T) {
|
|||
err = adaptor.EngineV2.Initial(blockchain, block.Header())
|
||||
assert.Nil(t, err)
|
||||
|
||||
round, _, highQC, _, _ := adaptor.EngineV2.GetProperties()
|
||||
round, _, highQC, _, _, _ := adaptor.EngineV2.GetPropertiesFaker()
|
||||
expectedQuorumCert := &utils.QuorumCert{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
Signatures: []utils.Signature{},
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ func TestYourTurnInitialV2(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
// round=1, so masternode[1] has YourTurn = True
|
||||
assert.True(t, b)
|
||||
assert.Equal(t, adaptor.EngineV2.GetCurrentRound(), utils.Round(1))
|
||||
assert.Equal(t, adaptor.EngineV2.GetCurrentRoundFaker(), utils.Round(1))
|
||||
|
||||
snap, err := adaptor.EngineV2.GetSnapshot(blockchain, block900.Header())
|
||||
assert.Nil(t, err)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ func TestHookPenaltyV2Mining(t *testing.T) {
|
|||
// set adaptor round/qc to that of 6299
|
||||
err = utils.DecodeBytesExtraFields(header6300.Extra, &extraField)
|
||||
assert.Nil(t, err)
|
||||
err = adaptor.EngineV2.ProcessQC(blockchain, extraField.QuorumCert)
|
||||
err = adaptor.EngineV2.ProcessQCFaker(blockchain, extraField.QuorumCert)
|
||||
assert.Nil(t, err)
|
||||
headerMining := &types.Header{
|
||||
ParentHash: header6300.ParentHash,
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) {
|
|||
}
|
||||
|
||||
voteMsg := <-engineV2.BroadcastCh
|
||||
poolSize := engineV2.GetVotePoolSize(voteMsg.(*utils.Vote))
|
||||
poolSize := engineV2.GetVotePoolSizeFaker(voteMsg.(*utils.Vote))
|
||||
|
||||
assert.Equal(t, poolSize, 1)
|
||||
assert.NotNil(t, voteMsg)
|
||||
assert.Equal(t, currentBlock.Hash(), voteMsg.(*utils.Vote).ProposedBlockInfo.Hash)
|
||||
|
||||
round, _, highestQC, _, _ := engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// Shoud trigger setNewRound
|
||||
assert.Equal(t, utils.Round(1), round)
|
||||
// Should not update the highestQC
|
||||
|
|
@ -53,7 +53,7 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) {
|
|||
// Trigger send vote again but for a new round
|
||||
voteMsg = <-engineV2.BroadcastCh
|
||||
assert.NotNil(t, voteMsg)
|
||||
round, _, highestQC, _, _ = engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
// Shoud trigger setNewRound
|
||||
assert.Equal(t, utils.Round(2), round)
|
||||
assert.Equal(t, utils.Round(1), highestQC.ProposedBlockInfo.Round)
|
||||
|
|
@ -70,7 +70,7 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) {
|
|||
// Trigger send vote again but for a new round
|
||||
voteMsg = <-engineV2.BroadcastCh
|
||||
assert.NotNil(t, voteMsg)
|
||||
round, _, highestQC, _, highestCommitBlock := engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, highestCommitBlock := engineV2.GetPropertiesFaker()
|
||||
// Shoud NOT trigger setNewRound as the new block parent QC is round 1 but the currentRound is already 2
|
||||
assert.Equal(t, utils.Round(3), round)
|
||||
assert.Equal(t, utils.Round(2), highestQC.ProposedBlockInfo.Round)
|
||||
|
|
@ -88,7 +88,7 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) {
|
|||
// Trigger send vote again but for a new round
|
||||
voteMsg = <-engineV2.BroadcastCh
|
||||
assert.NotNil(t, voteMsg)
|
||||
round, _, highestQC, _, highestCommitBlock = engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, highestCommitBlock = engineV2.GetPropertiesFaker()
|
||||
|
||||
assert.Equal(t, utils.Round(4), round)
|
||||
assert.Equal(t, utils.Round(3), highestQC.ProposedBlockInfo.Round)
|
||||
|
|
@ -117,7 +117,7 @@ func TestShouldNotCommitIfRoundsNotContinousFor3Rounds(t *testing.T) {
|
|||
assert.NotNil(t, voteMsg)
|
||||
assert.Equal(t, currentBlock.Hash(), voteMsg.(*utils.Vote).ProposedBlockInfo.Hash)
|
||||
|
||||
round, _, highestQC, _, highestCommitBlock := engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, highestCommitBlock := engineV2.GetPropertiesFaker()
|
||||
|
||||
grandGrandParentBlock := blockchain.GetBlockByNumber(902)
|
||||
// Shoud trigger setNewRound
|
||||
|
|
@ -139,7 +139,7 @@ func TestShouldNotCommitIfRoundsNotContinousFor3Rounds(t *testing.T) {
|
|||
// Trigger send vote again but for a new round
|
||||
voteMsg = <-engineV2.BroadcastCh
|
||||
assert.NotNil(t, voteMsg)
|
||||
round, _, highestQC, _, highestCommitBlock = engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, highestCommitBlock = engineV2.GetPropertiesFaker()
|
||||
grandGrandParentBlock = blockchain.GetBlockByNumber(903)
|
||||
|
||||
assert.Equal(t, utils.Round(6), round)
|
||||
|
|
@ -160,7 +160,7 @@ func TestShouldNotCommitIfRoundsNotContinousFor3Rounds(t *testing.T) {
|
|||
// Trigger send vote again but for a new round
|
||||
voteMsg = <-engineV2.BroadcastCh
|
||||
assert.NotNil(t, voteMsg)
|
||||
round, _, highestQC, _, highestCommitBlock = engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, highestCommitBlock = engineV2.GetPropertiesFaker()
|
||||
|
||||
assert.Equal(t, utils.Round(8), round)
|
||||
assert.Equal(t, utils.Round(7), highestQC.ProposedBlockInfo.Round)
|
||||
|
|
@ -193,7 +193,7 @@ func TestProposedBlockMessageHandlerSuccessfullyGenerateVote(t *testing.T) {
|
|||
assert.NotNil(t, voteMsg)
|
||||
assert.Equal(t, currentBlock.Hash(), voteMsg.(*utils.Vote).ProposedBlockInfo.Hash)
|
||||
|
||||
round, _, highestQC, _, _ := engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// Shoud trigger setNewRound
|
||||
assert.Equal(t, utils.Round(6), round)
|
||||
assert.Equal(t, extraField.QuorumCert.Signatures, highestQC.Signatures)
|
||||
|
|
@ -219,7 +219,7 @@ func TestShouldNotSetNewRound(t *testing.T) {
|
|||
t.Fatal("Fail propose proposedBlock handler", err)
|
||||
}
|
||||
|
||||
round, _, highestQC, _, _ := engineV2.GetProperties()
|
||||
round, _, highestQC, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// Shoud not trigger setNewRound
|
||||
assert.Equal(t, utils.Round(6), round)
|
||||
assert.Equal(t, extraField.QuorumCert.Signatures, highestQC.Signatures)
|
||||
|
|
@ -241,7 +241,7 @@ func TestShouldNotSendVoteMessageIfAlreadyVoteForThisRound(t *testing.T) {
|
|||
assert.NotNil(t, voteMsg)
|
||||
assert.Equal(t, currentBlock.Hash(), voteMsg.(*utils.Vote).ProposedBlockInfo.Hash)
|
||||
|
||||
round, _, _, highestVotedRound, _ := engineV2.GetProperties()
|
||||
round, _, _, _, highestVotedRound, _ := engineV2.GetPropertiesFaker()
|
||||
// Shoud trigger setNewRound
|
||||
assert.Equal(t, utils.Round(6), round)
|
||||
assert.Equal(t, utils.Round(6), highestVotedRound)
|
||||
|
|
@ -257,7 +257,7 @@ func TestShouldNotSendVoteMessageIfAlreadyVoteForThisRound(t *testing.T) {
|
|||
t.Fatal("Should not trigger vote")
|
||||
case <-time.After(5 * time.Second):
|
||||
// Shoud not trigger setNewRound
|
||||
round, _, _, highestVotedRound, _ = engineV2.GetProperties()
|
||||
round, _, _, _, highestVotedRound, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(6), round)
|
||||
assert.Equal(t, utils.Round(6), highestVotedRound)
|
||||
}
|
||||
|
|
@ -286,7 +286,7 @@ func TestShouldNotSendVoteMsgIfBlockInfoRoundNotEqualCurrentRound(t *testing.T)
|
|||
t.Fatal("Should not trigger vote")
|
||||
case <-time.After(5 * time.Second):
|
||||
// Shoud not trigger setNewRound
|
||||
round, _, _, _, _ := engineV2.GetProperties()
|
||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(8), round)
|
||||
}
|
||||
}
|
||||
|
|
@ -328,7 +328,7 @@ func TestShouldNotSendVoteMsgIfBlockNotExtendedFromAncestor(t *testing.T) {
|
|||
t.Fatal("Should not trigger vote")
|
||||
case <-time.After(5 * time.Second):
|
||||
// Shoud not trigger setNewRound
|
||||
round, _, _, _, _ := engineV2.GetProperties()
|
||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(7), round)
|
||||
}
|
||||
}
|
||||
|
|
@ -345,7 +345,7 @@ func TestShouldSendVoteMsg(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
round, _, _, _, _ := engineV2.GetProperties()
|
||||
round, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(i-900), round)
|
||||
vote := <-engineV2.BroadcastCh
|
||||
assert.Equal(t, round, vote.(*utils.Vote).ProposedBlockInfo.Round)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ func TestSyncInfoShouldSuccessfullyUpdateByQC(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
round, _, highestQuorumCert, _, highestCommitBlock := engineV2.GetProperties()
|
||||
round, _, highestQuorumCert, _, _, highestCommitBlock := engineV2.GetPropertiesFaker()
|
||||
// QC is parent block's qc, which is pointing at round 4, hence 4 + 1 = 5
|
||||
assert.Equal(t, utils.Round(5), round)
|
||||
assert.Equal(t, extraField.QuorumCert, highestQuorumCert)
|
||||
|
|
@ -66,7 +66,36 @@ func TestSyncInfoShouldSuccessfullyUpdateByTC(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
round, _, highestQuorumCert, _, _ := engineV2.GetProperties()
|
||||
round, _, highestQuorumCert, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(7), round)
|
||||
assert.Equal(t, extraField.QuorumCert, highestQuorumCert)
|
||||
}
|
||||
|
||||
func TestSkipVerifySyncInfoIfBothQcTcNotQualified(t *testing.T) {
|
||||
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, 0)
|
||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||
|
||||
// Make the Highest QC in syncInfo point to an old block to simulate it's no longer qualified
|
||||
parentBlock := blockchain.GetBlockByNumber(903)
|
||||
var extraField utils.ExtraFields_v2
|
||||
err := utils.DecodeBytesExtraFields(parentBlock.Extra(), &extraField)
|
||||
if err != nil {
|
||||
t.Fatal("Fail to decode extra data", err)
|
||||
}
|
||||
|
||||
highestTC := &utils.TimeoutCert{
|
||||
Round: utils.Round(5),
|
||||
Signatures: []utils.Signature{},
|
||||
}
|
||||
|
||||
syncInfoMsg := &utils.SyncInfo{
|
||||
HighestQuorumCert: extraField.QuorumCert,
|
||||
HighestTimeoutCert: highestTC,
|
||||
}
|
||||
|
||||
engineV2.SetPropertiesFaker(syncInfoMsg.HighestQuorumCert, syncInfoMsg.HighestTimeoutCert)
|
||||
|
||||
verified, err := engineV2.VerifySyncInfoMessage(blockchain, syncInfoMsg)
|
||||
assert.False(t, verified)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ func TestCountdownTimeoutToSendTimeoutMessage(t *testing.T) {
|
|||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||
|
||||
timeoutMsg := <-engineV2.BroadcastCh
|
||||
poolSize := engineV2.GetTimeoutPoolSize(timeoutMsg.(*utils.Timeout))
|
||||
poolSize := engineV2.GetTimeoutPoolSizeFaker(timeoutMsg.(*utils.Timeout))
|
||||
assert.Equal(t, poolSize, 1)
|
||||
assert.NotNil(t, timeoutMsg)
|
||||
assert.Equal(t, uint64(1350), timeoutMsg.(*utils.Timeout).GapNumber)
|
||||
|
|
@ -99,7 +99,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
|||
|
||||
err := engineV2.TimeoutHandler(blockchain, timeoutMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _ := engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(1), currentRound)
|
||||
timeoutMsg = &utils.Timeout{
|
||||
Round: utils.Round(1),
|
||||
|
|
@ -108,7 +108,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
|||
}
|
||||
err = engineV2.TimeoutHandler(blockchain, timeoutMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(1), currentRound)
|
||||
|
||||
// Send a timeout with different gap number, it shall not trigger timeout pool hook
|
||||
|
|
@ -119,7 +119,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
|||
}
|
||||
err = engineV2.TimeoutHandler(blockchain, timeoutMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(1), currentRound)
|
||||
|
||||
// Create a timeout message that should trigger timeout pool hook
|
||||
|
|
@ -134,7 +134,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
|
|||
|
||||
syncInfoMsg := <-engineV2.BroadcastCh
|
||||
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
|
||||
assert.NotNil(t, syncInfoMsg)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/accounts"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestShouldVerifyBlock(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
|
||||
// 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, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
// Happy path
|
||||
err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(901).Header(), true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Verify non-epoch switch block
|
||||
err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(902).Header(), true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
nonEpochSwitchWithValidators := blockchain.GetBlockByNumber(902).Header()
|
||||
nonEpochSwitchWithValidators.Validators = acc1Addr.Bytes()
|
||||
err = adaptor.VerifyHeader(blockchain, nonEpochSwitchWithValidators, true)
|
||||
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
||||
}
|
||||
|
||||
func TestShouldFailIfNotEnoughQCSignatures(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
|
||||
// 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, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
parentBlock := blockchain.GetBlockByNumber(901)
|
||||
proposedBlockInfo := &utils.BlockInfo{
|
||||
Hash: parentBlock.Hash(),
|
||||
Round: utils.Round(1),
|
||||
Number: parentBlock.Number(),
|
||||
}
|
||||
signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes())
|
||||
assert.Nil(t, err)
|
||||
var signatures []utils.Signature
|
||||
// Duplicate the signatures
|
||||
signatures = append(signatures, signedHash, signedHash, signedHash, signedHash, signedHash, signedHash)
|
||||
quorumCert := &utils.QuorumCert{
|
||||
ProposedBlockInfo: proposedBlockInfo,
|
||||
Signatures: signatures,
|
||||
}
|
||||
|
||||
extra := utils.ExtraFields_v2{
|
||||
Round: utils.Round(2),
|
||||
QuorumCert: quorumCert,
|
||||
}
|
||||
extraInBytes, err := extra.EncodeToBytes()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
|
||||
}
|
||||
headerWithDuplicatedSignatures := currentBlock.Header()
|
||||
headerWithDuplicatedSignatures.Extra = extraInBytes
|
||||
// Happy path
|
||||
err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true)
|
||||
assert.Equal(t, utils.ErrInvalidQC, err)
|
||||
|
||||
}
|
||||
193
consensus/tests/verify_header_test.go
Normal file
193
consensus/tests/verify_header_test.go
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/accounts"
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestShouldVerifyBlock(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
|
||||
// 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, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
// Happy path
|
||||
err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(901).Header(), true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Unhappy path
|
||||
|
||||
// Verify non-epoch switch block
|
||||
err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(902).Header(), true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
nonEpochSwitchWithValidators := blockchain.GetBlockByNumber(902).Header()
|
||||
nonEpochSwitchWithValidators.Validators = acc1Addr.Bytes()
|
||||
err = adaptor.VerifyHeader(blockchain, nonEpochSwitchWithValidators, true)
|
||||
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
||||
|
||||
noValidatorBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
noValidatorBlock.Validator = []byte{}
|
||||
err = adaptor.VerifyHeader(blockchain, noValidatorBlock, true)
|
||||
assert.Equal(t, consensus.ErrNoValidatorSignature, err)
|
||||
|
||||
blockFromFuture := blockchain.GetBlockByNumber(902).Header()
|
||||
blockFromFuture.Time = big.NewInt(time.Now().Unix() + 10000)
|
||||
err = adaptor.VerifyHeader(blockchain, blockFromFuture, true)
|
||||
assert.Equal(t, consensus.ErrFutureBlock, err)
|
||||
|
||||
invalidQcBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
invalidQcBlock.Extra = []byte{}
|
||||
err = adaptor.VerifyHeader(blockchain, invalidQcBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidV2Extra, err)
|
||||
|
||||
// Epoch switch
|
||||
invalidAuthNonceBlock := blockchain.GetBlockByNumber(901).Header()
|
||||
invalidAuthNonceBlock.Nonce = types.BlockNonce{123}
|
||||
err = adaptor.VerifyHeader(blockchain, invalidAuthNonceBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidVote, err)
|
||||
|
||||
emptyValidatorsBlock := blockchain.GetBlockByNumber(901).Header()
|
||||
emptyValidatorsBlock.Validators = []byte{}
|
||||
err = adaptor.VerifyHeader(blockchain, emptyValidatorsBlock, true)
|
||||
assert.Equal(t, utils.ErrEmptyEpochSwitchValidators, err)
|
||||
|
||||
invalidValidatorsSignerBlock := blockchain.GetBlockByNumber(901).Header()
|
||||
invalidValidatorsSignerBlock.Validators = []byte{123}
|
||||
err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidCheckpointSigners, err)
|
||||
|
||||
// non-epoch switch
|
||||
invalidValidatorsExistBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
invalidValidatorsExistBlock.Validators = []byte{123}
|
||||
err = adaptor.VerifyHeader(blockchain, invalidValidatorsExistBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
||||
|
||||
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb123"
|
||||
parentNotExistBlock := blockchain.GetBlockByNumber(901).Header()
|
||||
parentNotExistBlock.ParentHash = common.HexToHash(merkleRoot)
|
||||
err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true)
|
||||
assert.Equal(t, consensus.ErrUnknownAncestor, err)
|
||||
|
||||
tooFastMinedBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
tooFastMinedBlock.Time = big.NewInt(time.Now().Unix() - 2)
|
||||
err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidTimestamp, err)
|
||||
|
||||
invalidDifficultyBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
invalidDifficultyBlock.Difficulty = big.NewInt(2)
|
||||
err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true)
|
||||
assert.Equal(t, utils.ErrInvalidDifficulty, err)
|
||||
|
||||
// Creat an invalid QC round
|
||||
proposedBlockInfo := &utils.BlockInfo{
|
||||
Hash: blockchain.GetBlockByNumber(902).Hash(),
|
||||
Round: utils.Round(2),
|
||||
Number: blockchain.GetBlockByNumber(902).Number(),
|
||||
}
|
||||
// Genrate QC
|
||||
signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes())
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Error generate QC by creating signedHash: %v", err))
|
||||
}
|
||||
// Sign from acc 1, 2, 3
|
||||
acc1SignedHash := SignHashByPK(acc1Key, utils.VoteSigHash(proposedBlockInfo).Bytes())
|
||||
acc2SignedHash := SignHashByPK(acc2Key, utils.VoteSigHash(proposedBlockInfo).Bytes())
|
||||
acc3SignedHash := SignHashByPK(acc3Key, utils.VoteSigHash(proposedBlockInfo).Bytes())
|
||||
var signatures []utils.Signature
|
||||
signatures = append(signatures, signedHash, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
||||
quorumCert := &utils.QuorumCert{
|
||||
ProposedBlockInfo: proposedBlockInfo,
|
||||
Signatures: signatures,
|
||||
}
|
||||
|
||||
extra := utils.ExtraFields_v2{
|
||||
Round: utils.Round(2),
|
||||
QuorumCert: quorumCert,
|
||||
}
|
||||
extraInBytes, err := extra.EncodeToBytes()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
|
||||
}
|
||||
|
||||
invalidRoundBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
invalidRoundBlock.Extra = extraInBytes
|
||||
err = adaptor.VerifyHeader(blockchain, invalidRoundBlock, true)
|
||||
assert.Equal(t, utils.ErrRoundInvalid, err)
|
||||
|
||||
invalidPenaltiesExistBlock := blockchain.GetBlockByNumber(902).Header()
|
||||
invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20)
|
||||
err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true)
|
||||
assert.Equal(t, utils.ErrPenaltyListDoesNotMatch, err)
|
||||
|
||||
}
|
||||
|
||||
func TestShouldFailIfNotEnoughQCSignatures(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
|
||||
// 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, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
parentBlock := blockchain.GetBlockByNumber(901)
|
||||
proposedBlockInfo := &utils.BlockInfo{
|
||||
Hash: parentBlock.Hash(),
|
||||
Round: utils.Round(1),
|
||||
Number: parentBlock.Number(),
|
||||
}
|
||||
signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes())
|
||||
assert.Nil(t, err)
|
||||
var signatures []utils.Signature
|
||||
// Duplicate the signatures
|
||||
signatures = append(signatures, signedHash, signedHash, signedHash, signedHash, signedHash, signedHash)
|
||||
quorumCert := &utils.QuorumCert{
|
||||
ProposedBlockInfo: proposedBlockInfo,
|
||||
Signatures: signatures,
|
||||
}
|
||||
|
||||
extra := utils.ExtraFields_v2{
|
||||
Round: utils.Round(2),
|
||||
QuorumCert: quorumCert,
|
||||
}
|
||||
extraInBytes, err := extra.EncodeToBytes()
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
|
||||
}
|
||||
headerWithDuplicatedSignatures := currentBlock.Header()
|
||||
headerWithDuplicatedSignatures.Extra = extraInBytes
|
||||
// Happy path
|
||||
err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true)
|
||||
assert.Equal(t, utils.ErrInvalidQC, err)
|
||||
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
|
|||
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// initialised with nil and 0 round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -52,7 +52,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
|
|||
}
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
// Still using the initlised value because we did not yet go to the next round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -68,7 +68,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
|
|||
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
// The lockQC shall be the parent's QC round number
|
||||
assert.Equal(t, utils.Round(0), lockQuorumCert.ProposedBlockInfo.Round)
|
||||
// The highestQC proposedBlockInfo shall be the same as the one from its votes
|
||||
|
|
@ -100,7 +100,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
|
|||
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// initialised with nil and 0 round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -112,7 +112,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
|
|||
}
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
// Still using the initlised value because we did not yet go to the next round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -130,7 +130,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
|
|||
}
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
// Still using the initlised value because we did not yet go to the next round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -145,7 +145,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
|
|||
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, highestCommitBlock := engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, highestCommitBlock := engineV2.GetPropertiesFaker()
|
||||
// The lockQC shall be the parent's QC round number
|
||||
assert.Equal(t, utils.Round(4), lockQuorumCert.ProposedBlockInfo.Round)
|
||||
// The highestQC proposedBlockInfo shall be the same as the one from its votes
|
||||
|
|
@ -202,7 +202,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
blockInfo := &utils.BlockInfo{
|
||||
Hash: currentBlock.Hash(),
|
||||
Round: utils.Round(5),
|
||||
Number: big.NewInt(901),
|
||||
Number: big.NewInt(905),
|
||||
}
|
||||
voteSigningHash := utils.VoteSigHash(blockInfo)
|
||||
// Create two vote message which will not reach vote pool threshold
|
||||
|
|
@ -214,7 +214,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
|
||||
err := engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// initialised with nil and 0 round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -226,7 +226,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
}
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(5), currentRound)
|
||||
|
||||
// Create a vote message that should trigger vote pool hook
|
||||
|
|
@ -238,7 +238,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
// Check round has now changed from 5 to 6
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
// The lockQC shall be the parent's QC round number
|
||||
assert.Equal(t, utils.Round(4), lockQuorumCert.ProposedBlockInfo.Round)
|
||||
// The highestQC proposedBlockInfo shall be the same as the one from its votes
|
||||
|
|
@ -266,7 +266,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
|
||||
err = engineV2.TimeoutHandler(blockchain, timeoutMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(6), currentRound)
|
||||
timeoutMsg = &utils.Timeout{
|
||||
Round: utils.Round(6),
|
||||
|
|
@ -274,7 +274,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
}
|
||||
err = engineV2.TimeoutHandler(blockchain, timeoutMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(6), currentRound)
|
||||
|
||||
// Create a timeout message that should trigger timeout pool hook
|
||||
|
|
@ -300,7 +300,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
|
|||
sigatures := []utils.Signature{[]byte{1}, []byte{2}, []byte{3}}
|
||||
assert.ElementsMatch(t, tc.Signatures, sigatures)
|
||||
// Round shall be +1 now
|
||||
currentRound, _, _, _, _ = engineV2.GetProperties()
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(7), currentRound)
|
||||
}
|
||||
|
||||
|
|
@ -346,7 +346,7 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) {
|
|||
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// Still using the initlised value because we did not yet go to the next round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
|
@ -364,7 +364,7 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) {
|
|||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, highestCommitBlock := engineV2.GetProperties()
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, highestCommitBlock := engineV2.GetPropertiesFaker()
|
||||
// The lockQC shall be the parent's QC round number
|
||||
assert.Equal(t, utils.Round(5), lockQuorumCert.ProposedBlockInfo.Round)
|
||||
// The highestQC proposedBlockInfo shall be the same as the one from its votes
|
||||
|
|
@ -375,25 +375,80 @@ func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) {
|
|||
assert.Equal(t, big.NewInt(904), highestCommitBlock.Number)
|
||||
}
|
||||
|
||||
func TestProcessVoteMsgFailIfVerifyBlockInfoFail(t *testing.T) {
|
||||
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, 0)
|
||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||
|
||||
// Set round to 5
|
||||
engineV2.SetNewRoundFaker(blockchain, utils.Round(5), false)
|
||||
|
||||
// Start with vote messages
|
||||
blockInfo := &utils.BlockInfo{
|
||||
Hash: currentBlock.ParentHash(),
|
||||
Round: utils.Round(5),
|
||||
Number: big.NewInt(905),
|
||||
}
|
||||
voteSigningHash := utils.VoteSigHash(blockInfo)
|
||||
// Create two vote message which will not reach vote pool threshold
|
||||
signedHash := SignHashByPK(acc1Key, voteSigningHash.Bytes())
|
||||
voteMsg := &utils.Vote{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
Signature: signedHash,
|
||||
}
|
||||
|
||||
err := engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, lockQuorumCert, highestQuorumCert, _, _, _ := engineV2.GetPropertiesFaker()
|
||||
// initialised with nil and 0 round
|
||||
assert.Nil(t, lockQuorumCert)
|
||||
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
|
||||
|
||||
assert.Equal(t, utils.Round(5), currentRound)
|
||||
voteMsg = &utils.Vote{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
Signature: SignHashByPK(acc2Key, voteSigningHash.Bytes()),
|
||||
}
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
assert.Nil(t, err)
|
||||
currentRound, _, _, _, _, _ = engineV2.GetPropertiesFaker()
|
||||
assert.Equal(t, utils.Round(5), currentRound)
|
||||
|
||||
// Create a vote message that should trigger vote pool hook
|
||||
voteMsg = &utils.Vote{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
Signature: SignHashByPK(acc3Key, voteSigningHash.Bytes()),
|
||||
}
|
||||
|
||||
err = engineV2.VoteHandler(blockchain, voteMsg)
|
||||
expectedError := fmt.Errorf("[VerifyBlockInfo] chain header number does not match for the received blockInfo at hash: %v", blockInfo.Hash.Hex())
|
||||
assert.Equal(t, expectedError, err)
|
||||
}
|
||||
|
||||
func TestVerifyVoteMsg(t *testing.T) {
|
||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 915, params.TestXDPoSMockChainConfig, 0)
|
||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||
|
||||
blockInfo := &utils.BlockInfo{
|
||||
Hash: currentBlock.Hash(),
|
||||
Round: utils.Round(15),
|
||||
Round: utils.Round(14),
|
||||
Number: big.NewInt(915),
|
||||
}
|
||||
|
||||
// Invalid vote msg
|
||||
// Valid message but disqualified as the round does not match
|
||||
voteMsg := &utils.Vote{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
Signature: []byte{1},
|
||||
}
|
||||
|
||||
engineV2.SetNewRoundFaker(blockchain, utils.Round(15), false)
|
||||
verified, err := engineV2.VerifyVoteMessage(blockchain, voteMsg)
|
||||
assert.False(t, verified)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Invalid vote message with wrong signature
|
||||
engineV2.SetNewRoundFaker(blockchain, utils.Round(14), false)
|
||||
verified, err = engineV2.VerifyVoteMessage(blockchain, voteMsg)
|
||||
assert.False(t, verified)
|
||||
assert.Equal(t, "Error while verifying message: invalid signature length", err.Error())
|
||||
|
||||
// Valid vote message from a master node
|
||||
signHash, _ := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(blockInfo).Bytes())
|
||||
|
|
|
|||
|
|
@ -145,6 +145,87 @@ func TestNotBoardcastInvalidVote(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBoardcastButNotProcessDisqualifiedVotes(t *testing.T) {
|
||||
tester := newTester()
|
||||
handlerCounter := uint32(0)
|
||||
broadcastCounter := uint32(0)
|
||||
targetVotes := 0
|
||||
|
||||
tester.bfter.consensus.verifyVote = func(chain consensus.ChainReader, vote *utils.Vote) (bool, error) {
|
||||
return false, nil // return false but with nil in error means the message is valid but disqualified
|
||||
}
|
||||
|
||||
tester.bfter.consensus.voteHandler = func(chain consensus.ChainReader, vote *utils.Vote) error {
|
||||
atomic.AddUint32(&handlerCounter, 1)
|
||||
return nil
|
||||
}
|
||||
tester.bfter.broadcast.Vote = func(*utils.Vote) {
|
||||
atomic.AddUint32(&broadcastCounter, 1)
|
||||
}
|
||||
|
||||
vote := utils.Vote{ProposedBlockInfo: &utils.BlockInfo{}}
|
||||
tester.bfter.Vote(&vote)
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if int(handlerCounter) != targetVotes || int(broadcastCounter) != 1 {
|
||||
t.Fatalf("count mismatch: have %v on handler, %v on broadcast, want %v", handlerCounter, broadcastCounter, targetVotes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoardcastButNotProcessDisqualifiedTimeout(t *testing.T) {
|
||||
tester := newTester()
|
||||
handlerCounter := uint32(0)
|
||||
broadcastCounter := uint32(0)
|
||||
targetTimeout := 0
|
||||
|
||||
tester.bfter.consensus.verifyTimeout = func(chain consensus.ChainReader, timeout *utils.Timeout) (bool, error) {
|
||||
return false, nil // return false but with nil in error means the message is valid but disqualified
|
||||
}
|
||||
|
||||
tester.bfter.consensus.timeoutHandler = func(chain consensus.ChainReader, timeout *utils.Timeout) error {
|
||||
atomic.AddUint32(&handlerCounter, 1)
|
||||
return nil
|
||||
}
|
||||
tester.bfter.broadcast.Timeout = func(*utils.Timeout) {
|
||||
atomic.AddUint32(&broadcastCounter, 1)
|
||||
}
|
||||
|
||||
timeout := utils.Timeout{}
|
||||
tester.bfter.Timeout(&timeout)
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if int(handlerCounter) != targetTimeout || int(broadcastCounter) != 1 {
|
||||
t.Fatalf("count mismatch: have %v on handler, %v on broadcast, want %v", handlerCounter, broadcastCounter, targetTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoardcastButNotProcessDisqualifiedSyncInfo(t *testing.T) {
|
||||
tester := newTester()
|
||||
handlerCounter := uint32(0)
|
||||
broadcastCounter := uint32(0)
|
||||
targetSyncInfo := 0
|
||||
|
||||
tester.bfter.consensus.verifySyncInfo = func(chain consensus.ChainReader, syncInfo *utils.SyncInfo) (bool, error) {
|
||||
return false, nil // return false but with nil in error means the message is valid but disqualified
|
||||
}
|
||||
|
||||
tester.bfter.consensus.syncInfoHandler = func(chain consensus.ChainReader, syncInfo *utils.SyncInfo) error {
|
||||
atomic.AddUint32(&handlerCounter, 1)
|
||||
return nil
|
||||
}
|
||||
tester.bfter.broadcast.SyncInfo = func(*utils.SyncInfo) {
|
||||
atomic.AddUint32(&broadcastCounter, 1)
|
||||
}
|
||||
|
||||
syncInfo := utils.SyncInfo{}
|
||||
tester.bfter.SyncInfo(&syncInfo)
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if int(handlerCounter) != targetSyncInfo || int(broadcastCounter) != 1 {
|
||||
t.Fatalf("count mismatch: have %v on handler, %v on broadcast, want %v", handlerCounter, broadcastCounter, targetSyncInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: SyncInfo and Timeout Test, should be same as Vote.
|
||||
// Once all test on vote covered, then duplicate to others
|
||||
|
||||
|
|
@ -198,9 +279,7 @@ func TestTimeoutHandlerRoundNotEqual(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
tester.bfter.broadcast.Timeout = func(*utils.Timeout) {
|
||||
return
|
||||
}
|
||||
tester.bfter.broadcast.Timeout = func(*utils.Timeout) {}
|
||||
|
||||
timeoutMsg := &utils.Timeout{}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package bft
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
|
|
@ -40,7 +38,7 @@ type ConsensusFns struct {
|
|||
verifyTimeout func(consensus.ChainReader, *utils.Timeout) (bool, error)
|
||||
timeoutHandler func(consensus.ChainReader, *utils.Timeout) error
|
||||
|
||||
verifySyncInfo func(consensus.ChainReader, *utils.SyncInfo) error
|
||||
verifySyncInfo func(consensus.ChainReader, *utils.SyncInfo) (bool, error)
|
||||
syncInfoHandler func(consensus.ChainReader, *utils.SyncInfo) error
|
||||
}
|
||||
|
||||
|
|
@ -88,25 +86,25 @@ func (b *Bfter) Vote(vote *utils.Vote) error {
|
|||
|
||||
verified, err := b.consensus.verifyVote(b.blockChainReader, vote)
|
||||
|
||||
if err != nil || !verified {
|
||||
log.Error("Verify BFT Vote", "error", err, "verified", verified)
|
||||
if !verified {
|
||||
return fmt.Errorf("Fail to verify vote")
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("Verify BFT Vote", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
b.broadcastCh <- vote
|
||||
|
||||
err = b.consensus.voteHandler(b.blockChainReader, vote)
|
||||
if err != nil {
|
||||
if _, ok := err.(*utils.ErrIncomingMessageRoundTooFarFromCurrentRound); ok {
|
||||
log.Warn("vote round not equal", "error", err, "vote", vote.Hash())
|
||||
if verified {
|
||||
err = b.consensus.voteHandler(b.blockChainReader, vote)
|
||||
if err != nil {
|
||||
if _, ok := err.(*utils.ErrIncomingMessageRoundTooFarFromCurrentRound); ok {
|
||||
log.Warn("vote round not equal", "error", err, "vote", vote.Hash())
|
||||
return err
|
||||
}
|
||||
log.Error("handle BFT Vote", "error", err)
|
||||
return err
|
||||
}
|
||||
log.Error("handle BFT Vote", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (b *Bfter) Timeout(timeout *utils.Timeout) error {
|
||||
|
|
@ -117,24 +115,23 @@ func (b *Bfter) Timeout(timeout *utils.Timeout) error {
|
|||
}
|
||||
verified, err := b.consensus.verifyTimeout(b.blockChainReader, timeout)
|
||||
if err != nil {
|
||||
log.Error("Verify BFT Timeout", "error", err)
|
||||
log.Error("Verify BFT Timeout", "timeoutRound", timeout.Round, "timeoutGapNum", timeout.GapNumber, "error", err)
|
||||
return err
|
||||
}
|
||||
if !verified {
|
||||
log.Warn("Timeout message failed to verify", "timeoutRound", timeout.Round, "timeoutGapNum", timeout.GapNumber)
|
||||
return fmt.Errorf("Fail to verify the received timeout message")
|
||||
}
|
||||
b.broadcastCh <- timeout
|
||||
|
||||
err = b.consensus.timeoutHandler(b.blockChainReader, timeout)
|
||||
if err != nil {
|
||||
if _, ok := err.(*utils.ErrIncomingMessageRoundNotEqualCurrentRound); ok {
|
||||
log.Warn("timeout round not equal", "error", err)
|
||||
b.broadcastCh <- timeout
|
||||
if verified {
|
||||
err = b.consensus.timeoutHandler(b.blockChainReader, timeout)
|
||||
if err != nil {
|
||||
if _, ok := err.(*utils.ErrIncomingMessageRoundNotEqualCurrentRound); ok {
|
||||
log.Warn("timeout round not equal", "error", err)
|
||||
return err
|
||||
}
|
||||
log.Error("handle BFT Timeout", "error", err)
|
||||
return err
|
||||
}
|
||||
log.Error("handle BFT Timeout", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (b *Bfter) SyncInfo(syncInfo *utils.SyncInfo) error {
|
||||
|
|
@ -143,18 +140,20 @@ func (b *Bfter) SyncInfo(syncInfo *utils.SyncInfo) error {
|
|||
log.Trace("Discarded SyncInfo, known SyncInfo", "hash", syncInfo.Hash())
|
||||
return nil
|
||||
}
|
||||
err := b.consensus.verifySyncInfo(b.blockChainReader, syncInfo)
|
||||
verified, err := b.consensus.verifySyncInfo(b.blockChainReader, syncInfo)
|
||||
if err != nil {
|
||||
log.Error("Verify BFT SyncInfo", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
b.broadcastCh <- syncInfo
|
||||
|
||||
err = b.consensus.syncInfoHandler(b.blockChainReader, syncInfo)
|
||||
if err != nil {
|
||||
log.Error("handle BFT SyncInfo", "error", err)
|
||||
return err
|
||||
// Process only if verified and qualified
|
||||
if verified {
|
||||
err = b.consensus.syncInfoHandler(b.blockChainReader, syncInfo)
|
||||
if err != nil {
|
||||
log.Error("handle BFT SyncInfo", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue