From 328d555b9b0b88579c3ac57cafeb985c8328c006 Mon Sep 17 00:00:00 2001 From: Jerome Date: Sun, 30 Jan 2022 13:00:24 +1100 Subject: [PATCH] Xin 138 (#49) * check block header after vote pool reached * refactor test_helper to fix issues with tests randomly failing --- consensus/XDPoS/engines/engine_v2/engine.go | 12 ++ consensus/XDPoS/utils/pool.go | 7 +- consensus/XDPoS/utils/pool_test.go | 10 +- consensus/tests/adaptor_test.go | 40 ++-- consensus/tests/authorised_masternode_test.go | 55 ++---- consensus/tests/block_signer_test.go | 50 +++-- .../tests/blockchain_race_condition_test.go | 10 +- consensus/tests/mine_test.go | 10 +- consensus/tests/proposed_block_test.go | 35 +--- consensus/tests/test_helper.go | 185 +++++++----------- consensus/tests/vote_test.go | 75 ++++++- params/config.go | 2 +- 12 files changed, 258 insertions(+), 233 deletions(-) diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index c345c2e437..5605ecb389 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -568,10 +568,20 @@ func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote) thresholdReached, numberOfVotesInPool, pooledVotes := x.votePool.Add(voteMsg) if thresholdReached { log.Info(fmt.Sprintf("Vote pool threashold reached: %v, number of items in the pool: %v", thresholdReached, numberOfVotesInPool)) + + // Check if the block already exist, otherwise we try luck with the next vote + proposedBlock := chain.GetHeaderByHash(voteMsg.ProposedBlockInfo.Hash) + if proposedBlock == nil { + log.Warn("[voteHandler] The proposed block from vote message does not exist yet, wait for the next vote to try again", "Hash", voteMsg.ProposedBlockInfo.Hash, "Round", voteMsg.ProposedBlockInfo.Round) + return nil + } + err := x.onVotePoolThresholdReached(chain, pooledVotes, voteMsg) if err != nil { return err } + // clean up vote at the same poolKey. and pookKey is proposed block hash + x.votePool.ClearPoolKeyByObj(voteMsg) } return nil @@ -648,6 +658,8 @@ func (x *XDPoS_v2) timeoutHandler(timeout *utils.Timeout) error { if err != nil { return err } + // clean up timeout message at the same poolKey. and pookKey is proposed block hash + x.timeoutPool.ClearPoolKeyByObj(timeout) } return nil } diff --git a/consensus/XDPoS/utils/pool.go b/consensus/XDPoS/utils/pool.go index 4bfd91b6fb..43f0a09d4a 100644 --- a/consensus/XDPoS/utils/pool.go +++ b/consensus/XDPoS/utils/pool.go @@ -31,7 +31,6 @@ func (p *Pool) Add(obj PoolObj) (bool, int, map[common.Hash]PoolObj) { objListKeyed[obj.Hash()] = obj numOfItems := len(objListKeyed) if numOfItems >= p.threshold { - delete(p.objList, poolKey) return true, numOfItems, objListKeyed } return false, numOfItems, objListKeyed @@ -45,6 +44,12 @@ func (p *Pool) Size(obj PoolObj) int { return len(objListKeyed) } +// Given the pool object, clear all object under the same pool key +func (p *Pool) ClearPoolKeyByObj(obj PoolObj) { + poolKey := obj.PoolKey() + delete(p.objList, poolKey) +} + func (p *Pool) Clear() { p.objList = make(map[string]map[common.Hash]PoolObj) } diff --git a/consensus/XDPoS/utils/pool_test.go b/consensus/XDPoS/utils/pool_test.go index 5914c760ed..e4b6ab63b3 100644 --- a/consensus/XDPoS/utils/pool_test.go +++ b/consensus/XDPoS/utils/pool_test.go @@ -13,6 +13,7 @@ func TestPoolAdd(t *testing.T) { timeout1 := Timeout{Round: 1, Signature: []byte{1}} timeout2 := Timeout{Round: 1, Signature: []byte{2}} timeout3 := Timeout{Round: 1, Signature: []byte{3}} + timeout4 := Timeout{Round: 1, Signature: []byte{4}} thresholdReached, numOfItems, pooledTimeouts := pool.Add(&timeout1) assert.NotNil(pooledTimeouts) assert.Equal(1, numOfItems) @@ -29,8 +30,15 @@ func TestPoolAdd(t *testing.T) { assert.NotNil(pooledTimeouts) assert.Equal(2, numOfItems) - // Try to add one more to the same round, but that round threshold has already been reached, hence deleted + // Try to add one more to the same round, it should also trigger threshold thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout3) + assert.True(thresholdReached) + assert.NotNil(pooledTimeouts) + assert.Equal(3, numOfItems) + + // Only after manually clearned the pool at its objKey, we shall not have any value for this particular key + pool.ClearPoolKeyByObj(&timeout3) + thresholdReached, numOfItems, pooledTimeouts = pool.Add(&timeout4) assert.False(thresholdReached) assert.NotNil(pooledTimeouts) assert.Equal(1, numOfItems) diff --git a/consensus/tests/adaptor_test.go b/consensus/tests/adaptor_test.go index a13b0fef6d..7cbef6f9d0 100644 --- a/consensus/tests/adaptor_test.go +++ b/consensus/tests/adaptor_test.go @@ -44,10 +44,11 @@ func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) { if err != nil { t.Fatal(err) } - block11, err := insertBlock(blockchain, header) + block11, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block11) addressFromAdaptor, errorAdaptor = adaptor.Author(block11.Header()) if errorAdaptor != nil { @@ -177,24 +178,17 @@ func TestAdaptorGetMasternodesV2(t *testing.T) { adaptor := blockchain.Engine().(*XDPoS.XDPoS) blockNum := 11 blockCoinBase := "0x111000000000000000000000000000000123" - blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) - // it contains 3 master nodes - blockHeader.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c") + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) + // block 11 is the first v2 block, and is treated as epoch switch block - currentBlock, err := insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + blockchain.InsertBlock(currentBlock) masternodes1 := adaptor.GetMasternodes(blockchain, currentBlock.Header()) - assert.Equal(t, 3, len(masternodes1)) + assert.Equal(t, 4, len(masternodes1)) masternodes1ByNumber := adaptor.GetMasternodesByNumber(blockchain, currentBlock.NumberU64()) assert.True(t, reflect.DeepEqual(masternodes1, masternodes1ByNumber), "at block number", blockNum) for blockNum = 12; blockNum < 15; blockNum++ { - blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn) - currentBlock, err = insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn) + blockchain.InsertBlock(currentBlock) masternodes2 := adaptor.GetMasternodes(blockchain, currentBlock.Header()) assert.True(t, reflect.DeepEqual(masternodes1, masternodes2), "at block number", blockNum) masternodes2ByNumber := adaptor.GetMasternodesByNumber(blockchain, currentBlock.NumberU64()) @@ -215,25 +209,17 @@ func TestGetCurrentEpochSwitchBlock(t *testing.T) { // V2 blockNum := 11 blockCoinBase := "0x111000000000000000000000000000000123" - blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) - // it contains 3 master nodes - blockHeader.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c") - // block 11 is the first v2 block, and is treated as epoch switch block - currentBlock, err = insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) + blockchain.InsertBlock(currentBlock) currentCheckpointNumber, epochNum, err = adaptor.GetCurrentEpochSwitchBlock(blockchain, currentBlock.Number()) assert.Nil(t, err) assert.Equal(t, uint64(11), currentCheckpointNumber) assert.Equal(t, uint64(0), epochNum) for blockNum = 12; blockNum < 15; blockNum++ { - blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn) - currentBlock, err = insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn) + + blockchain.InsertBlock(currentBlock) currentCheckpointNumber, epochNum, err := adaptor.GetCurrentEpochSwitchBlock(blockchain, currentBlock.Number()) assert.Nil(t, err) assert.Equal(t, uint64(11), currentCheckpointNumber) diff --git a/consensus/tests/authorised_masternode_test.go b/consensus/tests/authorised_masternode_test.go index b6dba9f574..f3daac0f8c 100644 --- a/consensus/tests/authorised_masternode_test.go +++ b/consensus/tests/authorised_masternode_test.go @@ -32,7 +32,8 @@ func TestIsAuthorisedMNForConsensusV1(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinbaseA), } - block449, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + block449, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) + blockchain.InsertBlock(block449) if err != nil { t.Fatal(err) } @@ -57,10 +58,11 @@ func TestIsAuthorisedMNForConsensusV1(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(block450CoinbaseAddress), } - block450, err := insertBlock(blockchain, header) + block450, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450) isAuthorisedMN = engine.IsAuthorisedAddress(blockchain, block450.Header(), acc3Addr) assert.False(t, isAuthorisedMN) @@ -75,23 +77,14 @@ func TestIsAuthorisedMNForConsensusV2(t *testing.T) { adaptor := blockchain.Engine().(*XDPoS.XDPoS) blockNum := 11 blockCoinBase := "0x111000000000000000000000000000000123" - blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) - // it contains 3 master nodes - // xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1 - // xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff - // xdc065551F0dcAC6f00CAe11192D462db709bE3758c - blockHeader.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c") - // block 11 is the first v2 block, and is treated as epoch switch block - currentBlock, err := insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) + blockchain.InsertBlock(currentBlock) // As long as the address is in the master node list, they are all valid - isAuthorisedMN := adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff")) + isAuthorisedMN := adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")) assert.True(t, isAuthorisedMN) - isAuthorisedMN = adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc065551F0dcAC6f00CAe11192D462db709bE3758c")) + isAuthorisedMN = adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdc71562b71999873DB5b286dF957af199Ec94617F7")) assert.True(t, isAuthorisedMN) isAuthorisedMN = adaptor.IsAuthorisedAddress(blockchain, currentBlock.Header(), common.HexToAddress("xdcbanana")) @@ -105,47 +98,35 @@ func TestIsYourTurnConsensusV2(t *testing.T) { adaptor := blockchain.Engine().(*XDPoS.XDPoS) blockNum := 11 blockCoinBase := "0x111000000000000000000000000000000123" - blockHeader := createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) - // it contains 3 master nodes - // xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1 - // xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff - // xdc065551F0dcAC6f00CAe11192D462db709bE3758c - blockHeader.Validators = common.Hex2Bytes("0278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758c") - // block 11 is the first v2 block, and is treated as epoch switch block - currentBlock, err := insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 1, blockCoinBase, signer, signFn) + blockchain.InsertBlock(currentBlock) // The first address is valid - isYourTurn, err := adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1")) + isYourTurn, err := adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc703c4b2bD70c169f5717101CaeE543299Fc946C7")) assert.Nil(t, err) assert.True(t, isYourTurn) // The second and third address are not valid - isYourTurn, err = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff")) + isYourTurn, err = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")) assert.Nil(t, err) assert.False(t, isYourTurn) - isYourTurn, err = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc065551F0dcAC6f00CAe11192D462db709bE3758c")) + isYourTurn, err = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc71562b71999873DB5b286dF957af199Ec94617F7")) assert.Nil(t, err) assert.False(t, isYourTurn) // We continue to grow the chain which will increase the round number blockNum = 12 - blockHeader = createBlock(params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn) - currentBlock, err = insertBlock(blockchain, blockHeader) - if err != nil { - t.Fatal(err) - } + currentBlock = CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, int64(blockNum-10), blockCoinBase, signer, signFn) + blockchain.InsertBlock(currentBlock) adaptor.EngineV2.SetNewRoundFaker(1, false) - isYourTurn, _ = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1")) + isYourTurn, _ = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc703c4b2bD70c169f5717101CaeE543299Fc946C7")) assert.False(t, isYourTurn) - isYourTurn, _ = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff")) + isYourTurn, _ = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")) assert.True(t, isYourTurn) - isYourTurn, _ = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc065551F0dcAC6f00CAe11192D462db709bE3758c")) + isYourTurn, _ = adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc71562b71999873DB5b286dF957af199Ec94617F7")) assert.False(t, isYourTurn) } diff --git a/consensus/tests/block_signer_test.go b/consensus/tests/block_signer_test.go index 44caf27fdd..2ca29b7017 100644 --- a/consensus/tests/block_signer_test.go +++ b/consensus/tests/block_signer_test.go @@ -33,10 +33,11 @@ func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinbaseA), } - blockA, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + blockA, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(blockA) signers, err := GetSnapshotSigner(blockchain, blockA.Header()) if err != nil { @@ -67,10 +68,11 @@ func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase), } - block, err := insertBlock(blockchain, header) + block, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block) parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header()) if err != nil { t.Fatal(err) @@ -108,10 +110,12 @@ func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinbaseA), } - block449, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + block449, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block449) + parentBlock = block449 signers, err := GetSnapshotSigner(blockchain, block449.Header()) @@ -138,10 +142,11 @@ func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(block450CoinbaseAddress), } - block450, err := insertBlock(blockchain, header) + block450, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450) signers, err = GetSnapshotSigner(blockchain, block450.Header()) if err != nil { @@ -178,10 +183,11 @@ func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) { ParentHash: currentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinbaseA), } - blockA, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + blockA, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(blockA) signers, err := GetSnapshotSigner(blockchain, blockA.Header()) if err != nil { @@ -226,10 +232,11 @@ func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { ParentHash: currentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinbaseA), } - blockA, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + blockA, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(blockA) signers, err = GetSnapshotSigner(blockchain, blockA.Header()) if err != nil { @@ -260,10 +267,11 @@ func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { ParentHash: currentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase450B), } - block450B, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + block450B, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450B) signers, err = GetSnapshotSigner(blockchain, block450B.Header()) if err != nil { t.Fatal(err) @@ -289,7 +297,8 @@ func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { ParentHash: block450B.Hash(), Coinbase: common.HexToAddress(blockCoinBase451B), } - block451B, err := insertBlock(blockchain, header) + block451B, err := createBlockFromHeader(blockchain, header, nil) + blockchain.InsertBlock(block451B) if err != nil { t.Fatal(err) @@ -371,10 +380,11 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinbaseA), } - blockA, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx, transferTransaction}) + blockA, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx, transferTransaction}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(blockA) state, err = blockchain.State() if err != nil { t.Fatalf("Failed while trying to get blockchain state") @@ -412,10 +422,11 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase450B), } - block450B, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx, transferTransaction}) + block450B, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx, transferTransaction}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450B) state, err = blockchain.State() if err != nil { t.Fatalf("Failed while trying to get blockchain state") @@ -445,11 +456,11 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin ParentHash: block450B.Hash(), Coinbase: common.HexToAddress(blockCoinBase451B), } - block451B, err := insertBlock(blockchain, header) - + block451B, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block451B) signers, err = GetSnapshotSigner(blockchain, block450B.Header()) if err != nil { @@ -513,10 +524,11 @@ func TestVoteShouldNotBeAffectedByFork(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase450A), } - block450A, err := insertBlock(blockchain, header) + block450A, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450A) // Insert 451 A with vote blockCoinbase451A := "0xaaa0000000000000000000000000000000000451" @@ -532,10 +544,11 @@ func TestVoteShouldNotBeAffectedByFork(t *testing.T) { ParentHash: block450A.Hash(), Coinbase: common.HexToAddress(blockCoinbase451A), } - block451A, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + block451A, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block451A) // SignerList should be unchanged as the vote happen after GAP block signers, err = GetSnapshotSigner(blockchain, block451A.Header()) @@ -561,10 +574,11 @@ func TestVoteShouldNotBeAffectedByFork(t *testing.T) { ParentHash: parentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase450B), } - block450B, err := insertBlock(blockchain, header) + block450B, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450B) blockCoinBase451B := "0xbbb0000000000000000000000000000000000451" merkleRoot = "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" @@ -574,10 +588,11 @@ func TestVoteShouldNotBeAffectedByFork(t *testing.T) { ParentHash: block450B.Hash(), Coinbase: common.HexToAddress(blockCoinBase451B), } - block451B, err := insertBlock(blockchain, header) + block451B, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block451B) blockCoinBase452B := "0xbbb0000000000000000000000000000000000452" merkleRoot = "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" @@ -587,10 +602,11 @@ func TestVoteShouldNotBeAffectedByFork(t *testing.T) { ParentHash: block451B.Hash(), Coinbase: common.HexToAddress(blockCoinBase452B), } - block452B, err := insertBlock(blockchain, header) + block452B, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block452B) signers, err = GetSnapshotSigner(blockchain, block452B.Header()) if err != nil { t.Fatal(err) diff --git a/consensus/tests/blockchain_race_condition_test.go b/consensus/tests/blockchain_race_condition_test.go index 2156d78096..338d7faa7e 100644 --- a/consensus/tests/blockchain_race_condition_test.go +++ b/consensus/tests/blockchain_race_condition_test.go @@ -48,10 +48,11 @@ func TestRaceConditionOnBlockchainReadAndWrite(t *testing.T) { Coinbase: common.HexToAddress(blockCoinbaseA), } - blockA, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx, transferTransaction}) + blockA, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx, transferTransaction}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(blockA) state, err = blockchain.State() if err != nil { t.Fatalf("Failed while trying to get blockchain state") @@ -92,10 +93,11 @@ func TestRaceConditionOnBlockchainReadAndWrite(t *testing.T) { Difficulty: big.NewInt(2), } - block450B, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx, transferTransaction}) + block450B, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx, transferTransaction}) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block450B) if blockchain.CurrentHeader().Hash() != block450B.Hash() { t.Fatalf("the block with higher difficulty should be current header") } @@ -129,11 +131,11 @@ func TestRaceConditionOnBlockchainReadAndWrite(t *testing.T) { Coinbase: common.HexToAddress(blockCoinBase451B), Difficulty: big.NewInt(3), } - block451B, err := insertBlock(blockchain, header) - + block451B, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block451B) signers, err = GetSnapshotSigner(blockchain, block450B.Header()) if err != nil { diff --git a/consensus/tests/mine_test.go b/consensus/tests/mine_test.go index 3ed64bdad0..4f6ccf9221 100644 --- a/consensus/tests/mine_test.go +++ b/consensus/tests/mine_test.go @@ -31,10 +31,11 @@ func TestYourTurnInitialV2(t *testing.T) { Coinbase: common.HexToAddress(blockCoinbaseA), Extra: common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400"), } - block900, err := insertBlock(blockchain, header) + block900, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block900) // YourTurn is called before mine first v2 block b, err := adaptor.YourTurn(blockchain, block900.Header(), common.HexToAddress("xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1")) @@ -85,9 +86,9 @@ func TestUpdateMasterNodes(t *testing.T) { if err != nil { t.Fatal(err) } - parentBlock, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx}) + parentBlock, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}) assert.Nil(t, err) - + blockchain.InsertBlock(parentBlock) t.Logf("Inserting block from 1351 to 1800...") for i := 1351; i <= 1800; i++ { blockCoinbase := fmt.Sprintf("0xaaa000000000000000000000000000000000%4d", i) @@ -103,10 +104,11 @@ func TestUpdateMasterNodes(t *testing.T) { if err != nil { t.Fatal(err) } - block, err := insertBlock(blockchain, header) + block, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block) parentBlock = block } diff --git a/consensus/tests/proposed_block_test.go b/consensus/tests/proposed_block_test.go index 6aecbbd372..c2c8181391 100644 --- a/consensus/tests/proposed_block_test.go +++ b/consensus/tests/proposed_block_test.go @@ -43,11 +43,8 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) { // 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) - } + block12 := CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 2, blockCoinBase, signer, signFn) + blockchain.InsertBlock(block12) err = engineV2.ProposedBlockHandler(blockchain, block12.Header()) if err != nil { t.Fatal("Fail propose proposedBlock handler", err) @@ -63,11 +60,8 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) { // 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) - } + block13 := CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, block12, blockNum, 3, blockCoinBase, signer, signFn) + blockchain.InsertBlock(block13) err = engineV2.ProposedBlockHandler(blockchain, block13.Header()) if err != nil { t.Fatal("Fail propose proposedBlock handler", err) @@ -84,11 +78,8 @@ func TestShouldSendVoteMsgAndCommitGrandGrandParentBlock(t *testing.T) { // 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) - } + block14 := CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, block13, blockNum, 4, blockCoinBase, signer, signFn) + blockchain.InsertBlock(block14) err = engineV2.ProposedBlockHandler(blockchain, block14.Header()) if err != nil { t.Fatal("Fail propose proposedBlock handler", err) @@ -138,11 +129,8 @@ func TestShouldNotCommitIfRoundsNotContinousFor3Rounds(t *testing.T) { // 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) - } + block16 := CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 7, blockCoinBase, signer, signFn) + blockchain.InsertBlock(block16) err = engineV2.ProposedBlockHandler(blockchain, block16.Header()) if err != nil { t.Fatal("Fail propose proposedBlock handler", err) @@ -162,11 +150,8 @@ func TestShouldNotCommitIfRoundsNotContinousFor3Rounds(t *testing.T) { 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) - } + block17 := CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, block16, blockNum, 8, blockCoinBase, signer, signFn) + blockchain.InsertBlock(block17) err = engineV2.ProposedBlockHandler(blockchain, block17.Header()) if err != nil { t.Fatal("Fail propose proposedBlock handler", err) diff --git a/consensus/tests/test_helper.go b/consensus/tests/test_helper.go index cbf691b304..b61ec5f1ef 100644 --- a/consensus/tests/test_helper.go +++ b/consensus/tests/test_helper.go @@ -225,6 +225,7 @@ func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testi return ms } +// V1 consensus engine func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*BlockChain, *backends.SimulatedBackend, *types.Block, common.Address) { // Preparation var err error @@ -258,10 +259,11 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params ParentHash: currentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase), } - block, err := insertBlock(blockchain, header) + block, err := createBlockFromHeader(blockchain, header, nil) if err != nil { t.Fatal(err) } + blockchain.InsertBlock(block) currentBlock = block } // Update Signer as there is no previous signer assigned @@ -273,6 +275,7 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params return blockchain, backend, currentBlock, signer } +// V2 concensus engine 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 @@ -298,46 +301,16 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon } }() - var masternodesFromV1LastEpoch []common.Address - // Insert initial blocks for i := 1; i <= numOfBlocks; i++ { blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i) roundNumber := int64(i) - chainConfig.XDPoS.XDPoSV2Block.Int64() - header := createBlock(chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn) - // Inject the hardcoded master node list for the last v1 epoch block - if int64(i) == chainConfig.XDPoS.XDPoSV2Block.Int64() { - // reset extra - header.Extra = []byte{} - if len(header.Extra) < utils.ExtraVanity { - header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, utils.ExtraVanity-len(header.Extra))...) - } - header.Extra = header.Extra[:utils.ExtraVanity] - var masternodes []common.Address - masternodes = append(masternodes, acc1Addr, acc2Addr, acc3Addr, signer) - masternodesFromV1LastEpoch = masternodes - for _, masternode := range masternodes { - header.Extra = append(header.Extra, masternode[:]...) - } - header.Extra = append(header.Extra, make([]byte, utils.ExtraSeal)...) + block := CreateBlock(blockchain, chainConfig, currentBlock, i, roundNumber, blockCoinBase, signer, signFn) - // Sign all the things for v1 block use v1 sigHash function - sighash, err := signFn(accounts.Account{Address: signer}, blockchain.Engine().(*XDPoS.XDPoS).SigHash(header).Bytes()) - if err != nil { - t.Fatal(err) - } - copy(header.Extra[len(header.Extra)-utils.ExtraSeal:], sighash) - } else if (int64(i) == (chainConfig.XDPoS.XDPoSV2Block.Int64() + 1)) && masternodesFromV1LastEpoch != nil { // This is the first v2 block, we need to copy the last v1 epoch master node list and inject into v2 validators - for _, v := range masternodesFromV1LastEpoch { - header.Validators = append(header.Validators, v[:]...) - } - } - - block, err := insertBlock(blockchain, header) + err = blockchain.InsertBlock(block) if err != nil { t.Fatal(err) } - // Produce forked block for the last numOfForkedBlocks'th blocks if numOfForkedBlocks != 0 && i > numOfBlocks-numOfForkedBlocks { if currentForkBlock == nil { @@ -347,12 +320,9 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon forkedBlockRoundNumber := roundNumber + int64(numOfForkedBlocks) - forkedBlockHeader := createBlock(chainConfig, currentForkBlock, i, forkedBlockRoundNumber, forkedBlockCoinBase, signer, signFn) + forkedBlock := CreateBlock(blockchain, chainConfig, currentForkBlock, i, forkedBlockRoundNumber, forkedBlockCoinBase, signer, signFn) - forkedBlock, err := insertBlock(blockchain, forkedBlockHeader) - if err != nil { - t.Fatal(err) - } + blockchain.InsertBlock(forkedBlock) currentForkBlock = forkedBlock } currentBlock = block @@ -367,13 +337,12 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon 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 { +func CreateBlock(blockchain *BlockChain, chainConfig *params.ChainConfig, startingBlock *types.Block, blockNumber int, roundNumber int64, blockCoinBase string, signer common.Address, signFn func(account accounts.Account, hash []byte) ([]byte, error)) *types.Block { 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 { + if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.XDPoSV2Block) == 1 { // Build engine v2 compatible extra data field var extraField utils.ExtraFields_v2 var round utils.Round err := utils.DecodeBytesExtraFields(currentBlock.Extra(), &extraField) @@ -410,22 +379,59 @@ func createBlock(chainConfig *params.ChainConfig, startingBlock *types.Block, bl } header = &types.Header{ Root: common.HexToHash(merkleRoot), - Number: big.NewInt(int64(blockNumIteration)), + Number: big.NewInt(int64(blockNumber)), ParentHash: currentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase), Extra: extraInBytes, Validator: signedHash, } + if int64(blockNumber) == (chainConfig.XDPoS.XDPoSV2Block.Int64() + 1) { // This is the first v2 block, we need to copy the last v1 epoch master node list and inject into v2 validators + // Get last master node list from last v1 block + lastv1Block := blockchain.GetBlockByNumber(chainConfig.XDPoS.XDPoSV2Block.Uint64()) + masternodesFromV1LastEpoch := decodeMasternodesFromHeaderExtra(lastv1Block.Header()) + for _, v := range masternodesFromV1LastEpoch { + header.Validators = append(header.Validators, v[:]...) + } + } + } else { // V1 block header = &types.Header{ Root: common.HexToHash(merkleRoot), - Number: big.NewInt(int64(blockNumIteration)), + Number: big.NewInt(int64(blockNumber)), ParentHash: currentBlock.Hash(), Coinbase: common.HexToAddress(blockCoinBase), } + + // Inject the hardcoded master node list for the last v1 epoch block + if big.NewInt(int64(blockNumber)).Cmp(chainConfig.XDPoS.XDPoSV2Block) == 0 { + // reset extra + header.Extra = []byte{} + if len(header.Extra) < utils.ExtraVanity { + header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, utils.ExtraVanity-len(header.Extra))...) + } + header.Extra = header.Extra[:utils.ExtraVanity] + var masternodes []common.Address + masternodes = append(masternodes, acc1Addr, acc2Addr, acc3Addr, signer) + // masternodesFromV1LastEpoch = masternodes + for _, masternode := range masternodes { + header.Extra = append(header.Extra, masternode[:]...) + } + header.Extra = append(header.Extra, make([]byte, utils.ExtraSeal)...) + + // Sign all the things for v1 block use v1 sigHash function + sighash, err := signFn(accounts.Account{Address: signer}, blockchain.Engine().(*XDPoS.XDPoS).SigHash(header).Bytes()) + if err != nil { + panic(fmt.Errorf("Error when sign last v1 block hash during test block creation")) + } + copy(header.Extra[len(header.Extra)-utils.ExtraSeal:], sighash) + } } - return header + block, err := createBlockFromHeader(blockchain, header, nil) + if err != nil { + panic(fmt.Errorf("Fail to create block in test helper, %v", err)) + } + return block } func generateSignature(backend *backends.SimulatedBackend, adaptor *XDPoS.XDPoS, header *types.Header) error { @@ -442,54 +448,7 @@ func generateSignature(backend *backends.SimulatedBackend, adaptor *XDPoS.XDPoS, return nil } -// insert Block without transcation attached -func insertBlock(blockchain *BlockChain, header *types.Header) (*types.Block, error) { - header.ReceiptHash = common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - block, err := createXDPoSTestBlock( - blockchain, - header, - nil, - ) - if err != nil { - return nil, err - } - - err = blockchain.InsertBlock(block) - if err != nil { - return nil, err - } - return block, nil -} - -// insert Block with transcation attached -func insertBlockTxs(blockchain *BlockChain, header *types.Header, txs []*types.Transaction) (*types.Block, error) { - /* - header := types.Header{ - Root: common.HexToHash(root), - Number: big.NewInt(int64(blockNum)), - ParentHash: parentBlock.Hash(), - Coinbase: common.HexToAddress(blockCoinBase), - } - */ - header.ReceiptHash = common.HexToHash("0x9319777b782ba2c83a33c995481ff894ac96d9a92a1963091346a3e1e386705c") - block, err := createXDPoSTestBlock( - blockchain, - header, - txs, - ) - if err != nil { - return nil, err - } - - err = blockchain.InsertBlock(block) - if err != nil { - return nil, err - } - return block, nil -} - -//func createXDPoSTestBlock(bc *BlockChain, parentHash, coinbase string, number int, txs []*types.Transaction, receiptHash string, root common.Hash, customExtra []byte, signer common.Address) (*types.Block, error) { -func createXDPoSTestBlock(bc *BlockChain, customHeader *types.Header, txs []*types.Transaction) (*types.Block, error) { +func createBlockFromHeader(bc *BlockChain, customHeader *types.Header, txs []*types.Transaction) (*types.Block, error) { if customHeader.Extra == nil { extraSubstring := "d7830100018358444388676f312e31342e31856c696e75780000000000000000b185dc0d0e917d18e5dbf0746be6597d3331dd27ea0554e6db433feb2e81730b20b2807d33a1527bf43cd3bc057aa7f641609c2551ebe2fd575f4db704fbf38101" // Grabbed from existing mainnet block, it does not have any meaning except for the length validation customHeader.Extra, _ = hex.DecodeString(extraSubstring) @@ -500,28 +459,18 @@ func createXDPoSTestBlock(bc *BlockChain, customHeader *types.Header, txs []*typ } else { difficulty = customHeader.Difficulty } - /* - header := types.Header{ - ParentHash: common.HexToHash(parentHash), - UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - // ReceiptHash: types.EmptyRootHash, - ReceiptHash: common.HexToHash(receiptHash), - Root: root, - Coinbase: common.HexToAddress(coinbase), - Difficulty: big.NewInt(int64(1)), - Number: big.NewInt(int64(number)), - GasLimit: 1200000000, - Time: big.NewInt(int64(number * 10)), - Extra: customExtra, - Validator: signer[:], - } - */ + + // TODO: check if this is needed + if len(txs) != 0 { + customHeader.ReceiptHash = common.HexToHash("0x9319777b782ba2c83a33c995481ff894ac96d9a92a1963091346a3e1e386705c") + } else { + customHeader.ReceiptHash = common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") + } + header := types.Header{ - ParentHash: customHeader.ParentHash, - UncleHash: types.EmptyUncleHash, - TxHash: types.EmptyRootHash, - // ReceiptHash: types.EmptyRootHash, + ParentHash: customHeader.ParentHash, + UncleHash: types.EmptyUncleHash, + TxHash: types.EmptyRootHash, ReceiptHash: customHeader.ReceiptHash, Root: customHeader.Root, Coinbase: customHeader.Coinbase, @@ -543,7 +492,6 @@ func createXDPoSTestBlock(bc *BlockChain, customHeader *types.Header, txs []*typ return nil, fmt.Errorf("%v when get state", err) } gp := new(GasPool).AddGas(header.GasLimit) - // usedGas := uint64(0) var gasUsed = new(uint64) var receipts types.Receipts @@ -586,3 +534,12 @@ func createXDPoSTestBlock(bc *BlockChain, customHeader *types.Header, txs []*typ // return signedTX // } // */ + +// Get masternodes address from checkpoint Header. Only used for v1 last block +func decodeMasternodesFromHeaderExtra(checkpointHeader *types.Header) []common.Address { + masternodes := make([]common.Address, (len(checkpointHeader.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength) + for i := 0; i < len(masternodes); i++ { + copy(masternodes[i][:], checkpointHeader.Extra[utils.ExtraVanity+i*common.AddressLength:]) + } + return masternodes +} diff --git a/consensus/tests/vote_test.go b/consensus/tests/vote_test.go index e8cc066c95..a6299ad557 100644 --- a/consensus/tests/vote_test.go +++ b/consensus/tests/vote_test.go @@ -1,6 +1,7 @@ package tests import ( + "fmt" "math/big" "testing" @@ -24,7 +25,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQCForFistV2Round(t *te // Set round to 5 engineV2.SetNewRoundFaker(utils.Round(1), false) - // Create two timeout message which will not reach vote pool threshold + // Create two vote messages which will not reach vote pool threshold voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: []byte{1}, @@ -79,7 +80,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) { // Set round to 5 engineV2.SetNewRoundFaker(utils.Round(5), false) - // Create two timeout message which will not reach vote pool threshold + // Create two vote messages which will not reach vote pool threshold voteMsg := &utils.Vote{ ProposedBlockInfo: blockInfo, Signature: []byte{1}, @@ -265,3 +266,73 @@ func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) { currentRound, _, _, _, _ = engineV2.GetProperties() assert.Equal(t, utils.Round(7), currentRound) } + +func TestVoteMessageShallNotThrowErrorIfBlockNotYetExist(t *testing.T) { + blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0) + engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 + + // Create a new block but don't inject it into the chain yet + blockNum := 16 + blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", blockNum) + block := CreateBlock(blockchain, params.TestXDPoSMockChainConfigWithV2Engine, currentBlock, blockNum, 6, blockCoinBase, signer, signFn) + + blockInfo := &utils.BlockInfo{ + Hash: block.Header().Hash(), + Round: utils.Round(6), + Number: big.NewInt(16), + } + + // Set round to 6 + engineV2.SetNewRoundFaker(utils.Round(6), false) + // Create two vote messages which will not reach vote pool threshold + voteMsg := &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: []byte{1}, + } + + err := engineV2.VoteHandler(blockchain, voteMsg) + assert.Nil(t, err) + + voteMsg = &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: []byte{2}, + } + err = engineV2.VoteHandler(blockchain, voteMsg) + assert.Nil(t, err) + + // Create a vote message that should trigger vote pool hook, but it shall not produce any QC yet + voteMsg = &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: []byte{3}, + } + + err = engineV2.VoteHandler(blockchain, voteMsg) + assert.Nil(t, err) + 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) + + assert.Equal(t, utils.Round(6), currentRound) + + // Now, inject the block into the chain + blockchain.InsertBlock(block) + + voteMsg = &utils.Vote{ + ProposedBlockInfo: blockInfo, + Signature: []byte{4}, + } + + err = engineV2.VoteHandler(blockchain, voteMsg) + assert.Nil(t, err) + + currentRound, lockQuorumCert, highestQuorumCert, _, highestCommitBlock := engineV2.GetProperties() + // 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 + assert.Equal(t, highestQuorumCert.ProposedBlockInfo, voteMsg.ProposedBlockInfo) + assert.Equal(t, utils.Round(7), currentRound) + // Should trigger ProcessQC and trying to commit from blockNum of 16's grandgrandparent which is blockNum 14 with round 4 + assert.Equal(t, utils.Round(4), highestCommitBlock.Round) + assert.Equal(t, big.NewInt(14), highestCommitBlock.Number) +} diff --git a/params/config.go b/params/config.go index 37c754d36d..70d7c3098b 100644 --- a/params/config.go +++ b/params/config.go @@ -40,7 +40,7 @@ var ( CertThreshold: common.MaxMasternodesV2*2/3 + 1, } TestXDPoSV2Config = &V2{ - TimeoutWorkerDuration: 5, + TimeoutWorkerDuration: 10, CertThreshold: 3, }