From fb59230010b299605bee4a7c60622ccca2d952bf Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sun, 27 Jan 2019 10:01:09 -0600 Subject: [PATCH] blockchain: Use harness in threshold state tests. This refactors the threshold state tests in blockchain to use the recently introduced chaingen harness. Since these tests also require non-default choices, a new function named TestThresholdStateChoice is also introduced on the chaingen harness which allows both the state and the choice to be checked. --- blockchain/common_test.go | 34 ++++++ blockchain/thresholdstate_test.go | 179 ++++++++++-------------------- 2 files changed, 91 insertions(+), 122 deletions(-) diff --git a/blockchain/common_test.go b/blockchain/common_test.go index 993aa6eb..fa245f2e 100644 --- a/blockchain/common_test.go +++ b/blockchain/common_test.go @@ -461,6 +461,40 @@ func (g *chaingenHarness) TestThresholdState(id string, state ThresholdState) { } } +// TestThresholdStateChoice queries the threshold state from the current tip +// block associated with the harness generator and expects the returned state +// and choice to match the provided value. +func (g *chaingenHarness) TestThresholdStateChoice(id string, state ThresholdState, choice uint32) { + g.t.Helper() + + tipHash := g.Tip().BlockHash() + tipHeight := g.Tip().Header.Height + deploymentVer, err := g.lookupDeploymentVersion(id) + if err != nil { + g.t.Fatalf("block %q (hash %s, height %d) unexpected error when "+ + "retrieving threshold state: %v", g.TipName(), tipHash, tipHeight, + err) + } + + s, err := g.chain.NextThresholdState(&tipHash, deploymentVer, id) + if err != nil { + g.t.Fatalf("block %q (hash %s, height %d) unexpected error when "+ + "retrieving threshold state: %v", g.TipName(), tipHash, tipHeight, + err) + } + + if s.State != state { + g.t.Fatalf("block %q (hash %s, height %d) unexpected threshold "+ + "state for %s -- got %v, want %v", g.TipName(), tipHash, tipHeight, + id, s.State, state) + } + if s.Choice != choice { + g.t.Fatalf("block %q (hash %s, height %d) unexpected choice for %s -- "+ + "got %v, want %v", g.TipName(), tipHash, tipHeight, id, s.Choice, + choice) + } +} + // ForceTipReorg forces the chain instance associated with the generator to // reorganize the current tip of the main chain from the given block to the // given block. An error will result if the provided from block is not actually diff --git a/blockchain/thresholdstate_test.go b/blockchain/thresholdstate_test.go index eee6e606..ec0ab489 100644 --- a/blockchain/thresholdstate_test.go +++ b/blockchain/thresholdstate_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Decred developers +// Copyright (c) 2017-2019 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -12,7 +12,6 @@ import ( "github.com/decred/dcrd/blockchain/chaingen" "github.com/decred/dcrd/chaincfg" - "github.com/decred/dcrd/dcrutil" ) const ( @@ -139,78 +138,10 @@ func TestThresholdState(t *testing.T) { ExpireTime: math.MaxUint64, }) - // Create a test generator instance initialized with the genesis block - // as the tip. - g, err := chaingen.MakeGenerator(params) - if err != nil { - t.Fatalf("Failed to create generator: %v", err) - } - - // Create a new database and chain instance to run tests against. - chain, teardownFunc, err := chainSetup("thresholdstatetest", params) - if err != nil { - t.Fatalf("Failed to setup chain instance: %v", err) - } + // Create a test harness initialized with the genesis block as the tip. + g, teardownFunc := newChaingenHarness(t, params, "thresholdstatetest") defer teardownFunc() - // accepted processes the current tip block associated with the - // generator and expects it to be accepted to the main chain. - accepted := func() { - msgBlock := g.Tip() - blockHeight := msgBlock.Header.Height - block := dcrutil.NewBlock(msgBlock) - t.Logf("Testing block %s (hash %s, height %d)", - g.TipName(), block.Hash(), blockHeight) - - forkLen, isOrphan, err := chain.ProcessBlock(block, BFNone) - if err != nil { - t.Fatalf("block %q (hash %s, height %d) should "+ - "have been accepted: %v", g.TipName(), - block.Hash(), blockHeight, err) - } - - // Ensure the main chain and orphan flags match the values - // specified in the test. - isMainChain := !isOrphan && forkLen == 0 - if !isMainChain { - t.Fatalf("block %q (hash %s, height %d) unexpected main "+ - "chain flag -- got %v, want true", g.TipName(), - block.Hash(), blockHeight, isMainChain) - } - if isOrphan { - t.Fatalf("block %q (hash %s, height %d) unexpected "+ - "orphan flag -- got %v, want false", g.TipName(), - block.Hash(), blockHeight, isOrphan) - } - } - - // testThresholdState queries the threshold state from the current - // tip block associated with the generator and expects the returned - // state and choice to match the provided values. - testThresholdState := func(id string, state ThresholdState, choice uint32) { - tipHash := g.Tip().BlockHash() - s, err := chain.NextThresholdState(&tipHash, posVersion, id) - if err != nil { - t.Fatalf("block %q (hash %s, height %d) unexpected "+ - "error when retrieving threshold state: %v", - g.TipName(), tipHash, g.Tip().Header.Height, - err) - } - - if s.State != state { - t.Fatalf("block %q (hash %s, height %d) unexpected "+ - "threshold state for %s -- got %v, want %v", - g.TipName(), tipHash, g.Tip().Header.Height, - id, s.State, state) - } - if s.Choice != choice { - t.Fatalf("block %q (hash %s, height %d) unexpected "+ - "choice for %s -- got %v, want %v", - g.TipName(), tipHash, g.Tip().Header.Height, - id, s.Choice, choice) - } - } - // Shorter versions of useful params for convenience. ticketsPerBlock := int64(params.TicketsPerBlock) coinbaseMaturity := params.CoinbaseMaturity @@ -224,33 +155,37 @@ func TestThresholdState(t *testing.T) { ruleChangeDiv := int64(params.RuleChangeActivationDivisor) // --------------------------------------------------------------------- - // Premine. + // Block One. + // + // NOTE: The advance funcs on the harness are intentionally not used in + // these tests since they need to manually test the threshold state at + // all key heights. // --------------------------------------------------------------------- - // Add the required premine block. + // Add the required initial block. // - // genesis -> bp - g.CreatePremineBlock("bp", 0) + // genesis -> bfb + g.CreatePremineBlock("bfb", 0) g.AssertTipHeight(1) - accepted() - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.Accepted() + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to have mature coinbase outputs to work with. // - // genesis -> bp -> bm0 -> bm1 -> ... -> bm# + // genesis -> bfb -> bm0 -> bm1 -> ... -> bm# // --------------------------------------------------------------------- for i := uint16(0); i < coinbaseMaturity; i++ { blockName := fmt.Sprintf("bm%d", i) g.NextBlock(blockName, nil, nil) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(coinbaseMaturity) + 1) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the stake enabled height while @@ -268,11 +203,11 @@ func TestThresholdState(t *testing.T) { blockName := fmt.Sprintf("bse%d", i) g.NextBlock(blockName, nil, ticketOuts) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeEnabledHeight)) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the stake validation height while @@ -303,11 +238,11 @@ func TestThresholdState(t *testing.T) { g.NextBlock(blockName, nil, ticketOuts, chaingen.ReplaceBlockVersion(3)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight)) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach one block before the next stake @@ -330,13 +265,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceStakeVersion(0), chaingen.ReplaceVoteVersions(3)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + stakeVerInterval - 1)) g.AssertBlockVersion(3) g.AssertStakeVersion(0) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach one block before the next rule change @@ -358,13 +293,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceStakeVersion(3), chaingen.ReplaceVoteVersions(3)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval - 2)) g.AssertBlockVersion(3) g.AssertStakeVersion(3) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach one block before the next stake @@ -389,13 +324,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceStakeVersion(3), chaingen.ReplaceVoteVersions(4)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + stakeVerInterval*4 - 1)) g.AssertBlockVersion(3) g.AssertStakeVersion(3) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -422,13 +357,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceStakeVersion(4), chaingen.ReplaceVoteVersions(4)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*2 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to achieve proof-of-work block version lockin @@ -455,14 +390,14 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| vbTestDummy2No, 4)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*2 - 1 + powNumToCheck)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdDefined, invalidChoice) - testThresholdState(testDummy2ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdDefined, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdDefined, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -488,13 +423,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| vbTestDummy2No, 4)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*3 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdStarted, invalidChoice) - testThresholdState(testDummy2ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -518,13 +453,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| vbTestDummy2No, 3)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*4 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdStarted, invalidChoice) - testThresholdState(testDummy2ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -554,13 +489,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(voteBits, 4)) totalVotes += ticketsPerBlock g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*5 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdStarted, invalidChoice) - testThresholdState(testDummy2ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -598,13 +533,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(voteBits, 4)) totalVotes += ticketsPerBlock g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*6 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdStarted, invalidChoice) - testThresholdState(testDummy2ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy1ID, ThresholdStarted, invalidChoice) + g.TestThresholdStateChoice(testDummy2ID, ThresholdStarted, invalidChoice) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -629,13 +564,13 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1Yes| vbTestDummy2No, 4)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*7 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdLockedIn, testDummy1YesIndex) - testThresholdState(testDummy2ID, ThresholdFailed, testDummy2NoIndex) + g.TestThresholdStateChoice(testDummy1ID, ThresholdLockedIn, testDummy1YesIndex) + g.TestThresholdStateChoice(testDummy2ID, ThresholdFailed, testDummy2NoIndex) // --------------------------------------------------------------------- // Generate enough blocks to reach the next rule change interval with @@ -662,11 +597,11 @@ func TestThresholdState(t *testing.T) { chaingen.ReplaceVotes(vbPrevBlockValid|vbTestDummy1No| vbTestDummy2Yes, 4)) g.SaveTipCoinbaseOuts() - accepted() + g.Accepted() } g.AssertTipHeight(uint32(stakeValidationHeight + ruleChangeInterval*8 - 1)) g.AssertBlockVersion(4) g.AssertStakeVersion(4) - testThresholdState(testDummy1ID, ThresholdActive, testDummy1YesIndex) - testThresholdState(testDummy2ID, ThresholdFailed, testDummy2NoIndex) + g.TestThresholdStateChoice(testDummy1ID, ThresholdActive, testDummy1YesIndex) + g.TestThresholdStateChoice(testDummy2ID, ThresholdFailed, testDummy2NoIndex) }