add more propose block handler test

This commit is contained in:
Jianrong 2021-12-12 20:18:15 +11:00
parent 2a94cdebe5
commit 5f9fd80733
5 changed files with 158 additions and 80 deletions

View file

@ -74,9 +74,20 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 {
timeoutPool: timeoutPool,
votePool: votePool,
highestTimeoutCert: nil,
highestQuorumCert: nil,
highestTimeoutCert: &utils.TimeoutCert{
Round: utils.Round(0),
Signatures: []utils.Signature{},
},
highestQuorumCert: &utils.QuorumCert{
ProposedBlockInfo: &utils.BlockInfo{
Hash: common.Hash{},
Round: utils.Round(0),
Number: big.NewInt(0),
},
Signatures: []utils.Signature{},
},
highestVotedRound: utils.Round(0),
highestCommitBlock: nil,
}
// Add callback to the timer
timer.OnTimeoutFn = engine.onCountdownTimeout
@ -436,13 +447,6 @@ func (x *XDPoS_v2) VerifyHeader(chain consensus.ChainReader, header *types.Heade
return nil
}
// Utils for test to check currentRound value
func (x *XDPoS_v2) GetProperties() (utils.Round, *utils.QuorumCert, *utils.QuorumCert, utils.Round) {
x.lock.Lock()
defer x.lock.Unlock()
return x.currentRound, x.lockQuorumCert, x.highestQuorumCert, x.highestVotedRound
}
/*
SyncInfo workflow
*/
@ -704,7 +708,7 @@ func (x *XDPoS_v2) verifyTC(timeoutCert *utils.TimeoutCert) error {
func (x *XDPoS_v2) processQC(blockChainReader consensus.ChainReader, quorumCert *utils.QuorumCert) error {
log.Trace("[ProcessQC][Before]", "HighQC", x.highestQuorumCert)
// 1. Update HighestQC
if x.highestQuorumCert == nil || (quorumCert.ProposedBlockInfo.Round > x.highestQuorumCert.ProposedBlockInfo.Round) {
if quorumCert.ProposedBlockInfo.Round > x.highestQuorumCert.ProposedBlockInfo.Round {
x.highestQuorumCert = quorumCert
}
// 2. Get QC from header and update lockQuorumCert(lockQuorumCert is the parent of highestQC)
@ -745,7 +749,7 @@ func (x *XDPoS_v2) processQC(blockChainReader consensus.ChainReader, quorumCert
2. Check TC round >= node's currentRound. If yes, call setNewRound
*/
func (x *XDPoS_v2) processTC(timeoutCert *utils.TimeoutCert) error {
if x.highestTimeoutCert == nil || timeoutCert.Round > x.highestTimeoutCert.Round {
if timeoutCert.Round > x.highestTimeoutCert.Round {
x.highestTimeoutCert = timeoutCert
}
if timeoutCert.Round >= x.currentRound {
@ -898,14 +902,6 @@ func (x *XDPoS_v2) getCurrentRoundMasterNodes() []common.Address {
return []common.Address{}
}
/*
Testing tools
*/
func (x *XDPoS_v2) SetHighestQuorumCert(qc *utils.QuorumCert) {
x.highestQuorumCert = qc
}
func (x *XDPoS_v2) getSyncInfo() *utils.SyncInfo {
return &utils.SyncInfo{
HighestQuorumCert: x.highestQuorumCert,
@ -913,21 +909,6 @@ func (x *XDPoS_v2) getSyncInfo() *utils.SyncInfo {
}
}
func (x *XDPoS_v2) SetNewRoundFaker(newRound utils.Round, resetTimer bool) {
x.lock.Lock()
defer x.lock.Unlock()
// Reset a bunch of things
if resetTimer {
x.timeoutWorker.Reset()
}
x.currentRound = newRound
}
// Utils for test to check currentRound value
func (x *XDPoS_v2) GetCurrentRound() utils.Round {
return x.currentRound
}
//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) {
// XDPoS v1.0 switch to v2.0, skip commit
@ -978,3 +959,29 @@ func (x *XDPoS_v2) isExtendingFromAncestor(blockChainReader consensus.ChainReade
}
return false, nil
}
/*
Testing tools
*/
func (x *XDPoS_v2) SetNewRoundFaker(newRound utils.Round, resetTimer bool) {
x.lock.Lock()
defer x.lock.Unlock()
// Reset a bunch of things
if resetTimer {
x.timeoutWorker.Reset()
}
x.currentRound = newRound
}
// Utils for test to check currentRound value
func (x *XDPoS_v2) GetCurrentRound() utils.Round {
return x.currentRound
}
// Utils for test to check currentRound value
func (x *XDPoS_v2) GetProperties() (utils.Round, *utils.QuorumCert, *utils.QuorumCert, utils.Round) {
x.lock.Lock()
defer x.lock.Unlock()
return x.currentRound, x.lockQuorumCert, x.highestQuorumCert, x.highestVotedRound
}

View file

@ -157,33 +157,63 @@ func TestShouldNotSendVoteMsgIfBlockInfoRoundNotEqualCurrentRound(t *testing.T)
}
}
// TODO: Uncomment once confirmed the lockQuorumCert usage
// func TestShouldNotSendVoteMsgIfBlockNotExtendedFromAncestor(t *testing.T) {
// blockchain, _, currentBlock, _, forkedBlock := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 16)
// engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
/*
Block and round relationship diagram for this test
... - 13(3) - 14(4) - 15(5) - 16(6)
\ 14'(7)
*/
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)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// var extraField utils.ExtraFields_v2
// err := utils.DecodeBytesExtraFields(forkedBlock.Extra(), &extraField)
// if err != nil {
// t.Fatal("Fail to decode extra data", err)
// }
// // Set the lockQC and other pre-requist properties by block 16
// err = engineV2.ProposedBlockHandler(blockchain, currentBlock.Header())
// if err != nil {
// t.Fatal("Error while handling block 16", err)
// }
// // Now try with block 17 but from a different chain
// err = engineV2.ProposedBlockHandler(blockchain, forkedBlock.Header())
// if err != nil {
// t.Fatal("Fail propose proposedBlock handler", err)
// }
// // Should not receive anything from the channel
// select {
// case <-engineV2.BroadcastCh:
// t.Fatal("Should not trigger vote")
// case <-time.After(5 * time.Second):
// // Shoud not trigger setNewRound
// round, _, _, _ := engineV2.GetProperties()
// assert.Equal(t, utils.Round(8), round)
// }
// }
var extraField utils.ExtraFields_v2
err := utils.DecodeBytesExtraFields(forkedBlock.Extra(), &extraField)
if err != nil {
t.Fatal("Fail to decode extra data", err)
}
assert.Equal(t, utils.Round(9), extraField.Round)
// Set the lockQC and other pre-requist properties by block 16
err = engineV2.ProposedBlockHandler(blockchain, currentBlock.Header())
if err != nil {
t.Fatal("Error while handling block 16", err)
}
vote := <-engineV2.BroadcastCh
assert.Equal(t, utils.Round(6), vote.(*utils.Vote).ProposedBlockInfo.Round)
// Find the first forked block at block 14th
firstForkedBlock := blockchain.GetBlockByHash(blockchain.GetBlockByHash(forkedBlock.ParentHash()).ParentHash())
engineV2.SetNewRoundFaker(utils.Round(7), false)
err = engineV2.ProposedBlockHandler(blockchain, firstForkedBlock.Header())
if err != nil {
t.Fatal("Fail propose proposedBlock handler", err)
}
// Should not receive anything from the channel
select {
case <-engineV2.BroadcastCh:
t.Fatal("Should not trigger vote")
case <-time.After(5 * time.Second):
// Shoud not trigger setNewRound
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)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
// Block 11 is first v2 block
for i := 11; i < 14; i++ {
blockHeader := blockchain.GetBlockByNumber(uint64(i)).Header()
err := engineV2.ProposedBlockHandler(blockchain, blockHeader)
if err != nil {
t.Fatal(err)
}
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

@ -0,0 +1,31 @@
package tests
import (
"testing"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/params"
)
func TestSyncInfoForFirstV2BlockMsgWithoutQC(t *testing.T) {
// Block 11 is the first v2 block with starting round of 0
blockchain, _, currentBlock, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 11, 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)
}
syncInfoMsg := &utils.SyncInfo{
HighestQuorumCert: extraField.QuorumCert,
HighestTimeoutCert: nil, // Initial value?
}
err = engineV2.SyncInfoHandler(blockchain, syncInfoMsg)
if err != nil {
t.Fatal(err)
}
}

View file

@ -283,28 +283,28 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
currentBlock := blockchain.Genesis()
var currentForkBlock *types.Block
if numOfForkedBlocks != 0 {
currentForkBlock = blockchain.Genesis()
}
// Insert initial blocks
for i := 1; i <= numOfBlocks; i++ {
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
header := createBlock(chainConfig, currentBlock, i, blockCoinBase, signer, signFn)
roundNumber := int64(i) - chainConfig.XDPoS.XDPoSV2Block.Int64()
header := createBlock(chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn)
block, err := insertBlock(blockchain, header)
if err != nil {
t.Fatal(err)
}
currentBlock = block
}
if numOfForkedBlocks != 0 {
for i := 1; i <= numOfForkedBlocks; i++ {
// Produce forked block for the last numOfForkedBlocks'th blocks
if numOfForkedBlocks != 0 && i > numOfBlocks-numOfForkedBlocks {
if currentForkBlock == nil {
currentForkBlock = currentBlock
}
forkedBlockCoinBase := fmt.Sprintf("0x222000000000000000000000000000000%03d", i)
forkedBlockHeader := createBlock(chainConfig, currentForkBlock, i, forkedBlockCoinBase, signer, signFn)
forkedBlockRoundNumber := roundNumber + int64(numOfForkedBlocks)
forkedBlockHeader := createBlock(chainConfig, currentForkBlock, i, forkedBlockRoundNumber, forkedBlockCoinBase, signer, signFn)
forkedBlock, err := insertBlock(blockchain, forkedBlockHeader)
if err != nil {
@ -312,7 +312,9 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
}
currentForkBlock = forkedBlock
}
currentBlock = block
}
// Update Signer as there is no previous signer assigned
err = UpdateSigner(blockchain)
if err != nil {
@ -322,18 +324,26 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
return blockchain, backend, currentBlock, signer, currentForkBlock
}
func createBlock(chainConfig *params.ChainConfig, startingBlock *types.Block, blockNumIteration int, blockCoinBase string, signer common.Address, signFn func(account accounts.Account, hash []byte) ([]byte, error)) *types.Header {
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 {
currentBlock := startingBlock
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
var header *types.Header
// Build engine v2 compatible extra data field
if big.NewInt(int64(blockNumIteration)).Cmp(chainConfig.XDPoS.XDPoSV2Block) == 1 {
roundNumber := int64(blockNumIteration) - chainConfig.XDPoS.XDPoSV2Block.Int64()
var extraField utils.ExtraFields_v2
var round utils.Round
err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &extraField)
if err != nil {
round = utils.Round(0)
} else {
round = extraField.Round
}
proposedBlockInfo := &utils.BlockInfo{
Hash: currentBlock.Hash(),
Round: utils.Round(roundNumber - 1),
Number: big.NewInt(int64(blockNumIteration - 1)),
Round: round,
Number: currentBlock.Number(),
}
// Genrate QC
signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes())

View file

@ -33,7 +33,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te
err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
// Inilised with nil and 0 round
// initialised with nil and 0 round
assert.Nil(t, lockQuorumCert)
assert.Nil(t, highestQuorumCert)
assert.Equal(t, utils.Round(1), currentRound)
@ -88,7 +88,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
// Inilised with nil and 0 round
// initialised with nil and 0 round
assert.Nil(t, lockQuorumCert)
assert.Nil(t, highestQuorumCert)
assert.Equal(t, utils.Round(5), currentRound)
@ -174,7 +174,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
// Inilised with nil and 0 round
// initialised with nil and 0 round
assert.Nil(t, lockQuorumCert)
assert.Nil(t, highestQuorumCert)