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, timeoutPool: timeoutPool,
votePool: votePool, votePool: votePool,
highestTimeoutCert: nil, highestTimeoutCert: &utils.TimeoutCert{
highestQuorumCert: nil, 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), highestVotedRound: utils.Round(0),
highestCommitBlock: nil,
} }
// Add callback to the timer // Add callback to the timer
timer.OnTimeoutFn = engine.onCountdownTimeout timer.OnTimeoutFn = engine.onCountdownTimeout
@ -436,13 +447,6 @@ func (x *XDPoS_v2) VerifyHeader(chain consensus.ChainReader, header *types.Heade
return nil 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 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 { func (x *XDPoS_v2) processQC(blockChainReader consensus.ChainReader, quorumCert *utils.QuorumCert) error {
log.Trace("[ProcessQC][Before]", "HighQC", x.highestQuorumCert) log.Trace("[ProcessQC][Before]", "HighQC", x.highestQuorumCert)
// 1. Update HighestQC // 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 x.highestQuorumCert = quorumCert
} }
// 2. Get QC from header and update lockQuorumCert(lockQuorumCert is the parent of highestQC) // 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 2. Check TC round >= node's currentRound. If yes, call setNewRound
*/ */
func (x *XDPoS_v2) processTC(timeoutCert *utils.TimeoutCert) error { 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 x.highestTimeoutCert = timeoutCert
} }
if timeoutCert.Round >= x.currentRound { if timeoutCert.Round >= x.currentRound {
@ -898,14 +902,6 @@ func (x *XDPoS_v2) getCurrentRoundMasterNodes() []common.Address {
return []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 { func (x *XDPoS_v2) getSyncInfo() *utils.SyncInfo {
return &utils.SyncInfo{ return &utils.SyncInfo{
HighestQuorumCert: x.highestQuorumCert, 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 //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) { 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 // XDPoS v1.0 switch to v2.0, skip commit
@ -978,3 +959,29 @@ func (x *XDPoS_v2) isExtendingFromAncestor(blockChainReader consensus.ChainReade
} }
return false, nil 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) { Block and round relationship diagram for this test
// blockchain, _, currentBlock, _, forkedBlock := PrepareXDCTestBlockChainForV2Engine(t, 16, params.TestXDPoSMockChainConfigWithV2Engine, 16) ... - 13(3) - 14(4) - 15(5) - 16(6)
// engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 \ 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 var extraField utils.ExtraFields_v2
// err := utils.DecodeBytesExtraFields(forkedBlock.Extra(), &extraField) err := utils.DecodeBytesExtraFields(forkedBlock.Extra(), &extraField)
// if err != nil { if err != nil {
// t.Fatal("Fail to decode extra data", err) t.Fatal("Fail to decode extra data", err)
// } }
// // Set the lockQC and other pre-requist properties by block 16 assert.Equal(t, utils.Round(9), extraField.Round)
// err = engineV2.ProposedBlockHandler(blockchain, currentBlock.Header()) // Set the lockQC and other pre-requist properties by block 16
// if err != nil { err = engineV2.ProposedBlockHandler(blockchain, currentBlock.Header())
// t.Fatal("Error while handling block 16", err) 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()) vote := <-engineV2.BroadcastCh
// if err != nil { assert.Equal(t, utils.Round(6), vote.(*utils.Vote).ProposedBlockInfo.Round)
// t.Fatal("Fail propose proposedBlock handler", err)
// } // Find the first forked block at block 14th
// // Should not receive anything from the channel firstForkedBlock := blockchain.GetBlockByHash(blockchain.GetBlockByHash(forkedBlock.ParentHash()).ParentHash())
// select { engineV2.SetNewRoundFaker(utils.Round(7), false)
// case <-engineV2.BroadcastCh: err = engineV2.ProposedBlockHandler(blockchain, firstForkedBlock.Header())
// t.Fatal("Should not trigger vote") if err != nil {
// case <-time.After(5 * time.Second): t.Fatal("Fail propose proposedBlock handler", err)
// // Shoud not trigger setNewRound }
// round, _, _, _ := engineV2.GetProperties() // Should not receive anything from the channel
// assert.Equal(t, utils.Round(8), round) 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() currentBlock := blockchain.Genesis()
var currentForkBlock *types.Block var currentForkBlock *types.Block
if numOfForkedBlocks != 0 {
currentForkBlock = blockchain.Genesis()
}
// Insert initial blocks // Insert initial blocks
for i := 1; i <= numOfBlocks; i++ { for i := 1; i <= numOfBlocks; i++ {
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i) blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
roundNumber := int64(i) - chainConfig.XDPoS.XDPoSV2Block.Int64()
header := createBlock(chainConfig, currentBlock, i, blockCoinBase, signer, signFn) header := createBlock(chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn)
block, err := insertBlock(blockchain, header) block, err := insertBlock(blockchain, header)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
currentBlock = block
} // Produce forked block for the last numOfForkedBlocks'th blocks
if numOfForkedBlocks != 0 { if numOfForkedBlocks != 0 && i > numOfBlocks-numOfForkedBlocks {
for i := 1; i <= numOfForkedBlocks; i++ { if currentForkBlock == nil {
currentForkBlock = currentBlock
}
forkedBlockCoinBase := fmt.Sprintf("0x222000000000000000000000000000000%03d", i) 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) forkedBlock, err := insertBlock(blockchain, forkedBlockHeader)
if err != nil { if err != nil {
@ -312,7 +312,9 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
} }
currentForkBlock = forkedBlock currentForkBlock = forkedBlock
} }
currentBlock = block
} }
// Update Signer as there is no previous signer assigned // Update Signer as there is no previous signer assigned
err = UpdateSigner(blockchain) err = UpdateSigner(blockchain)
if err != nil { if err != nil {
@ -322,18 +324,26 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
return blockchain, backend, currentBlock, signer, currentForkBlock 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 currentBlock := startingBlock
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
var header *types.Header var header *types.Header
// Build engine v2 compatible extra data field // Build engine v2 compatible extra data field
if big.NewInt(int64(blockNumIteration)).Cmp(chainConfig.XDPoS.XDPoSV2Block) == 1 { 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{ proposedBlockInfo := &utils.BlockInfo{
Hash: currentBlock.Hash(), Hash: currentBlock.Hash(),
Round: utils.Round(roundNumber - 1), Round: round,
Number: big.NewInt(int64(blockNumIteration - 1)), Number: currentBlock.Number(),
} }
// Genrate QC // Genrate QC
signedHash, err := signFn(accounts.Account{Address: signer}, utils.VoteSigHash(proposedBlockInfo).Bytes()) 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) err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err) assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties() currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
// Inilised with nil and 0 round // initialised with nil and 0 round
assert.Nil(t, lockQuorumCert) assert.Nil(t, lockQuorumCert)
assert.Nil(t, highestQuorumCert) assert.Nil(t, highestQuorumCert)
assert.Equal(t, utils.Round(1), currentRound) assert.Equal(t, utils.Round(1), currentRound)
@ -88,7 +88,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
err := engineV2.VoteHandler(blockchain, voteMsg) err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err) assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties() currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
// Inilised with nil and 0 round // initialised with nil and 0 round
assert.Nil(t, lockQuorumCert) assert.Nil(t, lockQuorumCert)
assert.Nil(t, highestQuorumCert) assert.Nil(t, highestQuorumCert)
assert.Equal(t, utils.Round(5), currentRound) assert.Equal(t, utils.Round(5), currentRound)
@ -174,7 +174,7 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {
err := engineV2.VoteHandler(blockchain, voteMsg) err := engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err) assert.Nil(t, err)
currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties() currentRound, lockQuorumCert, highestQuorumCert, _ := engineV2.GetProperties()
// Inilised with nil and 0 round // initialised with nil and 0 round
assert.Nil(t, lockQuorumCert) assert.Nil(t, lockQuorumCert)
assert.Nil(t, highestQuorumCert) assert.Nil(t, highestQuorumCert)