Merge pull request #33 from hash-laboratories-au/XIN-98-commit-workflow

Commit grand grand parent block(continous rounds) if enough votes or …
This commit is contained in:
Jerome 2022-01-01 16:21:19 +11:00 committed by GitHub
commit d43940a837
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 238 additions and 64 deletions

View file

@ -831,6 +831,7 @@ func (x *XDPoS_v2) sendVote(chainReader consensus.ChainReader, blockInfo *utils.
signedHash, err := x.signSignature(utils.VoteSigHash(blockInfo))
if err != nil {
log.Error("signSignature when sending out Vote", "BlockInfoHash", blockInfo.Hash, "Error", err)
return err
}
@ -840,7 +841,11 @@ func (x *XDPoS_v2) sendVote(chainReader consensus.ChainReader, blockInfo *utils.
Signature: signedHash,
}
x.voteHandler(chainReader, voteMsg)
err = x.voteHandler(chainReader, voteMsg)
if err != nil {
log.Error("sendVote error", "BlockInfoHash", blockInfo.Hash, "Error", err)
return err
}
x.broadcastToBftChannel(voteMsg)
return nil
}
@ -854,6 +859,7 @@ func (x *XDPoS_v2) sendVote(chainReader consensus.ChainReader, blockInfo *utils.
func (x *XDPoS_v2) sendTimeout() error {
signedHash, err := x.signSignature(utils.TimeoutSigHash(&x.currentRound))
if err != nil {
log.Error("signSignature when sending out TC", "Error", err)
return err
}
timeoutMsg := &utils.Timeout{
@ -861,7 +867,11 @@ func (x *XDPoS_v2) sendTimeout() error {
Signature: signedHash,
}
x.timeoutHandler(timeoutMsg)
err = x.timeoutHandler(timeoutMsg)
if err != nil {
log.Error("TimeoutHandler error", "TimeoutRound", timeoutMsg.Round, "Error", err)
return err
}
x.broadcastToBftChannel(timeoutMsg)
return nil
}
@ -930,36 +940,49 @@ func (x *XDPoS_v2) getSyncInfo() *utils.SyncInfo {
}
}
//TODO: find parent and grandparent and grandgrandparent block, check round number, if so, commit grandgrandparent
func (x *XDPoS_v2) commitBlocks(blockCahinReader consensus.ChainReader, proposedBlockHeader *types.Header, proposedBlockRound *utils.Round) (bool, error) {
//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 *utils.Round) (bool, error) {
// XDPoS v1.0 switch to v2.0, skip commit
if big.NewInt(0).Sub(proposedBlockHeader.Number, big.NewInt(2)).Cmp(x.config.XDPoSV2Block) <= 0 {
return false, nil
}
// Find the last two parent block and check their rounds are the continous
parentBlock := blockCahinReader.GetHeaderByHash(proposedBlockHeader.ParentHash)
// Find the last two parent block and check their rounds are the continuous
parentBlock := blockChainReader.GetHeaderByHash(proposedBlockHeader.ParentHash)
var decodedExtraField utils.ExtraFields_v2
err := utils.DecodeBytesExtraFields(parentBlock.Extra, &decodedExtraField)
if err != nil {
log.Error("Fail to execute first DecodeBytesExtraFields for commiting block", "ProposedBlockHash", proposedBlockHeader.Hash())
return false, err
}
if *proposedBlockRound-1 != decodedExtraField.Round {
log.Debug("[commitBlocks] Rounds not continuous(parent) found when committing block", "proposedBlockRound", proposedBlockRound, "decodedExtraField.Round", decodedExtraField.Round, "proposedBlockHeaderHash", proposedBlockHeader.Hash())
return false, nil
}
// If parent round is continous, we check grandparent
grandParentBlock := blockCahinReader.GetHeaderByHash(parentBlock.ParentHash)
// If parent round is continuous, we check grandparent
grandParentBlock := blockChainReader.GetHeaderByHash(parentBlock.ParentHash)
err = utils.DecodeBytesExtraFields(grandParentBlock.Extra, &decodedExtraField)
if err != nil {
log.Error("Fail to execute second DecodeBytesExtraFields for commiting block", "parentBlockHash", parentBlock.Hash())
return false, err
}
if *proposedBlockRound-2 != decodedExtraField.Round {
log.Debug("[commitBlocks] Rounds not continuous(grand parent) found when committing block", "proposedBlockRound", proposedBlockRound, "decodedExtraField.Round", decodedExtraField.Round, "proposedBlockHeaderHash", proposedBlockHeader.Hash())
return false, nil
}
// TODO: Commit the grandParent block
return true, nil
// Commit the grandParent block
if x.highestCommitBlock == nil || (x.highestCommitBlock.Round < decodedExtraField.Round && x.highestCommitBlock.Number.Cmp(grandParentBlock.Number) == -1) {
x.highestCommitBlock = &utils.BlockInfo{
Number: grandParentBlock.Number,
Hash: grandParentBlock.Hash(),
Round: decodedExtraField.Round,
}
log.Debug("👴 Successfully committed block", "Committed block Hash", x.highestCommitBlock.Hash, "Committed round", x.highestCommitBlock.Round)
return true, nil
}
// Everything else, fail to commit
return false, nil
}
func (x *XDPoS_v2) isExtendingFromAncestor(blockChainReader consensus.ChainReader, currentBlock *utils.BlockInfo, ancestorBlock *utils.BlockInfo) (bool, error) {
@ -969,10 +992,11 @@ func (x *XDPoS_v2) isExtendingFromAncestor(blockChainReader consensus.ChainReade
for i := 0; i < blockNumDiff; i++ {
parentBlock := blockChainReader.GetHeaderByHash(nextBlockHash)
if parentBlock == nil {
return false, fmt.Errorf("Could not find its parent block when checking whether currentBlock %v is extending from the ancestorBlock %v", currentBlock.Number, ancestorBlock.Number)
return false, fmt.Errorf("Could not find its parent block when checking whether currentBlock %v with hash %v is extending from the ancestorBlock %v", currentBlock.Number, currentBlock.Hash, ancestorBlock.Number)
} else {
nextBlockHash = parentBlock.ParentHash
}
log.Debug("[isExtendingFromAncestor] Found parent block", "CurrentBlockHash", currentBlock.Hash, "ParentHash", nextBlockHash)
}
if nextBlockHash == ancestorBlock.Hash {
@ -1001,8 +1025,8 @@ func (x *XDPoS_v2) GetCurrentRound() utils.Round {
}
// Utils for test to check currentRound value
func (x *XDPoS_v2) GetProperties() (utils.Round, *utils.QuorumCert, *utils.QuorumCert, utils.Round) {
func (x *XDPoS_v2) GetProperties() (utils.Round, *utils.QuorumCert, *utils.QuorumCert, utils.Round, *utils.BlockInfo) {
x.lock.Lock()
defer x.lock.Unlock()
return x.currentRound, x.lockQuorumCert, x.highestQuorumCert, x.highestVotedRound
return x.currentRound, x.lockQuorumCert, x.highestQuorumCert, x.highestVotedRound, x.highestCommitBlock
}

View file

@ -13,7 +13,7 @@ import (
)
func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) {
blockchain, backend, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 10, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, backend, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 10, params.TestXDPoSMockChainConfigWithV2Engine, 0)
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
addressFromAdaptor, errorAdaptor := adaptor.Author(currentBlock.Header())

View file

@ -10,7 +10,7 @@ import (
)
func TestCountdownTimeoutToSendTimeoutMessage(t *testing.T) {
blockchain, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
engineV2.SetNewRoundFaker(utils.Round(1), true)

View file

@ -1,6 +1,7 @@
package tests
import (
"fmt"
"testing"
"time"
@ -10,9 +11,9 @@ import (
"github.com/stretchr/testify/assert"
)
func TestProcessFirstV2BlockAndSendVoteMsg(t *testing.T) {
func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) {
// Block 11 is the first v2 block with round of 1
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
var extraField utils.ExtraFields_v2
@ -33,16 +34,159 @@ func TestProcessFirstV2BlockAndSendVoteMsg(t *testing.T) {
assert.NotNil(t, voteMsg)
assert.Equal(t, currentBlock.Hash(), voteMsg.(*utils.Vote).ProposedBlockInfo.Hash)
round, _, highestQC, _ := engineV2.GetProperties()
round, _, highestQC, _, _ := engineV2.GetProperties()
// Shoud trigger setNewRound
assert.Equal(t, utils.Round(1), round)
// Should not update the highestQC
assert.Equal(t, utils.Round(0), highestQC.ProposedBlockInfo.Round)
// Insert another Block, but it won't trigger commit
blockNum := 12
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum)
blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 2, blockCoinBase, signer, signFn)
block12, err := insertBlock(blockchain, blockHeader)
if err != nil {
t.Fatal(err)
}
err = engineV2.ProposedBlockHandler(blockchain, block12.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
// Trigger send vote again but for a new round
voteMsg = <-engineV2.BroadcastCh
assert.NotNil(t, voteMsg)
round, _, highestQC, _, _ = engineV2.GetProperties()
// Shoud trigger setNewRound
assert.Equal(t, utils.Round(2), round)
assert.Equal(t, utils.Round(1), highestQC.ProposedBlockInfo.Round)
// Insert one more Block, but still won't trigger commit
blockNum = 13
blockCoinBase = fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum)
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, block12, blockNum, 3, blockCoinBase, signer, signFn)
block13, err := insertBlock(blockchain, blockHeader)
if err != nil {
t.Fatal(err)
}
err = engineV2.ProposedBlockHandler(blockchain, block13.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
// Trigger send vote again but for a new round
voteMsg = <-engineV2.BroadcastCh
assert.NotNil(t, voteMsg)
round, _, highestQC, _, highestCommitBlock := engineV2.GetProperties()
// 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)
assert.Nil(t, highestCommitBlock)
// Insert one more Block, this time will trigger commit
blockNum = 14
blockCoinBase = fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum)
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, block13, blockNum, 4, blockCoinBase, signer, signFn)
block14, err := insertBlock(blockchain, blockHeader)
if err != nil {
t.Fatal(err)
}
err = engineV2.ProposedBlockHandler(blockchain, block14.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
// Trigger send vote again but for a new round
voteMsg = <-engineV2.BroadcastCh
assert.NotNil(t, voteMsg)
round, _, highestQC, _, highestCommitBlock = engineV2.GetProperties()
assert.Equal(t, utils.Round(4), round)
assert.Equal(t, utils.Round(3), highestQC.ProposedBlockInfo.Round)
assert.Equal(t, currentBlock.Hash(), highestCommitBlock.Hash)
assert.Equal(t, currentBlock.Number(), highestCommitBlock.Number)
assert.Equal(t, utils.Round(1), highestCommitBlock.Round)
}
func TestShouldNotCommitIfRoundsNotContinousFor3Rounds(t *testing.T) {
// Block 11 is the first v2 block with round of 1
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
var extraField utils.ExtraFields_v2
err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &extraField)
if err != nil {
t.Fatal("Fail to decode extra data", err)
}
err = engineV2.ProposedBlockHandler(blockchain, currentBlock.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
voteMsg := <-engineV2.BroadcastCh
assert.NotNil(t, voteMsg)
assert.Equal(t, currentBlock.Hash(), voteMsg.(*utils.Vote).ProposedBlockInfo.Hash)
round, _, highestQC, _, highestCommitBlock := engineV2.GetProperties()
grandGrandParentBlock := blockchain.GetBlockByNumber(12)
// Shoud trigger setNewRound
assert.Equal(t, utils.Round(5), round)
assert.Equal(t, utils.Round(4), highestQC.ProposedBlockInfo.Round)
assert.Equal(t, grandGrandParentBlock.Hash(), highestCommitBlock.Hash)
assert.Equal(t, grandGrandParentBlock.Number(), highestCommitBlock.Number)
assert.Equal(t, utils.Round(2), highestCommitBlock.Round)
// Injecting new block which have gaps in the round number (Round 7 instead of 6)
blockNum := 16
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum)
blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 7, blockCoinBase, signer, signFn)
block16, err := insertBlock(blockchain, blockHeader)
if err != nil {
t.Fatal(err)
}
err = engineV2.ProposedBlockHandler(blockchain, block16.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
// Trigger send vote again but for a new round
voteMsg = <-engineV2.BroadcastCh
assert.NotNil(t, voteMsg)
round, _, highestQC, _, highestCommitBlock = engineV2.GetProperties()
grandGrandParentBlock = blockchain.GetBlockByNumber(13)
assert.Equal(t, utils.Round(6), round)
assert.Equal(t, utils.Round(5), highestQC.ProposedBlockInfo.Round)
// It commit its grandgrandparent block
assert.Equal(t, grandGrandParentBlock.Hash(), highestCommitBlock.Hash)
assert.Equal(t, grandGrandParentBlock.Number(), highestCommitBlock.Number)
assert.Equal(t, utils.Round(3), highestCommitBlock.Round)
blockNum = 17
blockCoinBase = fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum)
blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, block16, blockNum, 8, blockCoinBase, signer, signFn)
block17, err := insertBlock(blockchain, blockHeader)
if err != nil {
t.Fatal(err)
}
err = engineV2.ProposedBlockHandler(blockchain, block17.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
// Trigger send vote again but for a new round
voteMsg = <-engineV2.BroadcastCh
assert.NotNil(t, voteMsg)
round, _, highestQC, _, highestCommitBlock = engineV2.GetProperties()
assert.Equal(t, utils.Round(8), round)
assert.Equal(t, utils.Round(7), highestQC.ProposedBlockInfo.Round)
// Should NOT commit, the `grandGrandParentBlock` is still on blockNum 13
assert.Equal(t, grandGrandParentBlock.Hash(), highestCommitBlock.Hash)
assert.Equal(t, grandGrandParentBlock.Number(), highestCommitBlock.Number)
assert.Equal(t, utils.Round(3), highestCommitBlock.Round)
}
func TestProposedBlockMessageHandlerSuccessfullyGenerateVote(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set current round to 5
@ -63,7 +207,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.GetProperties()
// Shoud trigger setNewRound
assert.Equal(t, utils.Round(6), round)
assert.Equal(t, extraField.QuorumCert.Signatures, highestQC.Signatures)
@ -72,7 +216,7 @@ func TestProposedBlockMessageHandlerSuccessfullyGenerateVote(t *testing.T) {
// Should not set new round if proposedBlockInfo round is less than currentRound.
// NOTE: This shall not even happen because we have `verifyQC` before being passed into ProposedBlockHandler
func TestShouldNotSetNewRound(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set current round to 6
@ -89,14 +233,14 @@ func TestShouldNotSetNewRound(t *testing.T) {
t.Fatal("Fail propose proposedBlock handler", err)
}
round, _, highestQC, _ := engineV2.GetProperties()
round, _, highestQC, _, _ := engineV2.GetProperties()
// Shoud not trigger setNewRound
assert.Equal(t, utils.Round(6), round)
assert.Equal(t, extraField.QuorumCert.Signatures, highestQC.Signatures)
}
func TestShouldNotSendVoteMessageIfAlreadyVoteForThisRound(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set current round to 5
@ -111,7 +255,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.GetProperties()
// Shoud trigger setNewRound
assert.Equal(t, utils.Round(6), round)
assert.Equal(t, utils.Round(6), highestVotedRound)
@ -127,14 +271,14 @@ 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.GetProperties()
assert.Equal(t, utils.Round(6), round)
assert.Equal(t, utils.Round(6), highestVotedRound)
}
}
func TestShouldNotSendVoteMsgIfBlockInfoRoundNotEqualCurrentRound(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set current round to 8
@ -156,7 +300,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.GetProperties()
assert.Equal(t, utils.Round(8), round)
}
}
@ -168,7 +312,7 @@ func TestShouldNotSendVoteMsgIfBlockInfoRoundNotEqualCurrentRound(t *testing.T)
*/
func TestShouldNotSendVoteMsgIfBlockNotExtendedFromAncestor(t *testing.T) {
// Block number 15, 16 have forks and forkedBlock is the 16th
blockchain, _, currentBlock, _, forkedBlock := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 3)
blockchain, _, currentBlock, _, _, forkedBlock := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 3)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
var extraField utils.ExtraFields_v2
@ -198,14 +342,14 @@ 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.GetProperties()
assert.Equal(t, utils.Round(7), round)
}
}
func TestShouldSendVoteMsg(t *testing.T) {
// Block number 15, 16 have forks and forkedBlock is the 16th
blockchain, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 13, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 13, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Block 11 is first v2 block
@ -215,7 +359,7 @@ func TestShouldSendVoteMsg(t *testing.T) {
if err != nil {
t.Fatal(err)
}
round, _, _, _ := engineV2.GetProperties()
round, _, _, _, _ := engineV2.GetProperties()
assert.Equal(t, utils.Round(i-10), round)
vote := <-engineV2.BroadcastCh
assert.Equal(t, round, vote.(*utils.Vote).ProposedBlockInfo.Round)

View file

@ -1,6 +1,7 @@
package tests
import (
"math/big"
"testing"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
@ -11,7 +12,7 @@ import (
func TestSyncInfoShouldSuccessfullyUpdateByQC(t *testing.T) {
// Block 11 is the first v2 block with starting round of 0
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
var extraField utils.ExtraFields_v2
@ -32,15 +33,17 @@ func TestSyncInfoShouldSuccessfullyUpdateByQC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
round, _, highestQuorumCert, _ := engineV2.GetProperties()
round, _, highestQuorumCert, _, highestCommitBlock := engineV2.GetProperties()
// 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)
assert.Equal(t, utils.Round(2), highestCommitBlock.Round)
assert.Equal(t, big.NewInt(12), highestCommitBlock.Number)
}
func TestSyncInfoShouldSuccessfullyUpdateByTC(t *testing.T) {
// Block 11 is the first v2 block with starting round of 0
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
var extraField utils.ExtraFields_v2
@ -63,7 +66,7 @@ func TestSyncInfoShouldSuccessfullyUpdateByTC(t *testing.T) {
if err != nil {
t.Fatal(err)
}
round, _, highestQuorumCert, _ := engineV2.GetProperties()
round, _, highestQuorumCert, _, _ := engineV2.GetProperties()
assert.Equal(t, utils.Round(7), round)
assert.Equal(t, extraField.QuorumCert, highestQuorumCert)
}

View file

@ -266,7 +266,7 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params
return blockchain, backend, currentBlock, signer
}
func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig, numOfForkedBlocks int) (*BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, *types.Block) {
func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig, numOfForkedBlocks int) (*BlockChain, *backends.SimulatedBackend, *types.Block, common.Address, func(account accounts.Account, hash []byte) ([]byte, error), *types.Block) {
// Preparation
var err error
backend := getCommonBackend(t, chainConfig)
@ -321,7 +321,7 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
t.Fatal(err)
}
return blockchain, backend, currentBlock, signer, currentForkBlock
return blockchain, backend, currentBlock, signer, signFn, currentForkBlock
}
func createBlock(chainConfig *params.ChainConfig, startingBlock *types.Block, blockNumIteration int, roundNumber int64, blockCoinBase string, signer common.Address, signFn func(account accounts.Account, hash []byte) ([]byte, error)) *types.Header {

View file

@ -11,7 +11,7 @@ import (
// Timeout handler
func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
blockchain, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set round to 1
@ -24,7 +24,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
err := engineV2.TimeoutHandler(timeoutMsg)
assert.Nil(t, err)
currentRound, _, _, _ := engineV2.GetProperties()
currentRound, _, _, _, _ := engineV2.GetProperties()
assert.Equal(t, utils.Round(1), currentRound)
timeoutMsg = &utils.Timeout{
Round: utils.Round(1),
@ -32,7 +32,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
}
err = engineV2.TimeoutHandler(timeoutMsg)
assert.Nil(t, err)
currentRound, _, _, _ = engineV2.GetProperties()
currentRound, _, _, _, _ = engineV2.GetProperties()
assert.Equal(t, utils.Round(1), currentRound)
// Create a timeout message that should trigger timeout pool hook
timeoutMsg = &utils.Timeout{
@ -45,7 +45,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
syncInfoMsg := <-engineV2.BroadcastCh
currentRound, _, _, _ = engineV2.GetProperties()
currentRound, _, _, _, _ = engineV2.GetProperties()
assert.NotNil(t, syncInfoMsg)
@ -62,7 +62,7 @@ func TestTimeoutMessageHandlerSuccessfullyGenerateTCandSyncInfo(t *testing.T) {
}
func TestThrowErrorIfTimeoutMsgRoundNotEqualToCurrentRound(t *testing.T) {
blockchain, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set round to 3

View file

@ -13,7 +13,7 @@ import (
// VoteHandler
func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
blockInfo := &utils.BlockInfo{
@ -32,7 +32,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
// initialised with nil and 0 round
assert.Nil(t, lockQuorumCert)
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
@ -43,7 +43,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
}
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ = engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
// 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)
@ -58,7 +58,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ = engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
// 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
@ -68,7 +68,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
}
func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
blockInfo := &utils.BlockInfo{
@ -87,7 +87,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
// initialised with nil and 0 round
assert.Nil(t, lockQuorumCert)
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
@ -98,7 +98,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
}
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ = engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, _ = engineV2.GetProperties()
// 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)
@ -113,17 +113,20 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ = engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, highestCommitBlock := engineV2.GetProperties()
// 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
assert.Equal(t, highestQuorumCert.ProposedBlockInfo, voteMsg.ProposedBlockInfo)
// Check round has now changed from 5 to 6
assert.Equal(t, utils.Round(6), currentRound)
// Should trigger ProcessQC and trying to commit from blockNum of 16's grandgrandparent which is blockNum 13 with round 3
assert.Equal(t, utils.Round(3), highestCommitBlock.Round)
assert.Equal(t, big.NewInt(13), highestCommitBlock.Number)
}
func TestThrowErrorIfVoteMsgRoundNotEqualToCurrentRound(t *testing.T) {
blockchain, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
blockInfo := &utils.BlockInfo{
@ -153,7 +156,7 @@ func TestThrowErrorIfVoteMsgRoundNotEqualToCurrentRound(t *testing.T) {
}
func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Set round to 5
@ -173,7 +176,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
currentRound, lockQuorumCert, highestQuorumCert, _, _ := engineV2.GetProperties()
// initialised with nil and 0 round
assert.Nil(t, lockQuorumCert)
assert.Equal(t, utils.Round(0), highestQuorumCert.ProposedBlockInfo.Round)
@ -185,7 +188,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
}
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, _, _, _ = engineV2.GetProperties()
currentRound, _, _, _, _ = engineV2.GetProperties()
assert.Equal(t, utils.Round(5), currentRound)
// Create a vote message that should trigger vote pool hook
@ -197,7 +200,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.GetProperties()
// 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
@ -225,7 +228,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
err = engineV2.TimeoutHandler(timeoutMsg)
assert.Nil(t, err)
currentRound, _, _, _ = engineV2.GetProperties()
currentRound, _, _, _, _ = engineV2.GetProperties()
assert.Equal(t, utils.Round(6), currentRound)
timeoutMsg = &utils.Timeout{
Round: utils.Round(6),
@ -233,7 +236,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
}
err = engineV2.TimeoutHandler(timeoutMsg)
assert.Nil(t, err)
currentRound, _, _, _ = engineV2.GetProperties()
currentRound, _, _, _, _ = engineV2.GetProperties()
assert.Equal(t, utils.Round(6), currentRound)
// Create a timeout message that should trigger timeout pool hook
@ -259,6 +262,6 @@ 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.GetProperties()
assert.Equal(t, utils.Round(7), currentRound)
}

View file

@ -19,7 +19,7 @@ type broadcastTimeoutFn func(*utils.Timeout)
type broadcastSyncInfoFn func(*utils.SyncInfo)
type Bfter struct {
blockCahinReader consensus.ChainReader
blockChainReader consensus.ChainReader
broadcastCh chan interface{}
quit chan struct{}
consensus ConsensusFns
@ -48,7 +48,7 @@ type BroadcastFns struct {
SyncInfo broadcastSyncInfoFn
}
func New(broadcasts BroadcastFns, blockCahinReader *core.BlockChain) *Bfter {
func New(broadcasts BroadcastFns, blockChainReader *core.BlockChain) *Bfter {
knownVotes, _ := lru.New(messageLimit)
knownSyncInfos, _ := lru.New(messageLimit)
knownTimeouts, _ := lru.New(messageLimit)
@ -59,7 +59,7 @@ func New(broadcasts BroadcastFns, blockCahinReader *core.BlockChain) *Bfter {
knownVotes: knownVotes,
knownSyncInfos: knownSyncInfos,
knownTimeouts: knownTimeouts,
blockCahinReader: blockCahinReader,
blockChainReader: blockChainReader,
}
}
@ -92,7 +92,7 @@ func (b *Bfter) Vote(vote *utils.Vote) error {
}
b.broadcastCh <- vote
err = b.consensus.voteHandler(b.blockCahinReader, vote)
err = b.consensus.voteHandler(b.blockChainReader, vote)
if err != nil {
log.Error("handle BFT Vote", "error", err)
return err
@ -137,7 +137,7 @@ func (b *Bfter) SyncInfo(syncInfo *utils.SyncInfo) error {
b.broadcastCh <- syncInfo
err = b.consensus.syncInfoHandler(b.blockCahinReader, syncInfo)
err = b.consensus.syncInfoHandler(b.blockChainReader, syncInfo)
if err != nil {
log.Error("handle BFT SyncInfo", "error", err)
return err