You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
15 KiB

state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
add support for block pruning via ABCI Commit response (#4588) * Added BlockStore.DeleteBlock() * Added initial block pruner prototype * wip * Added BlockStore.PruneBlocks() * Added consensus setting for block pruning * Added BlockStore base * Error on replay if base does not have blocks * Handle missing blocks when sending VoteSetMaj23Message * Error message tweak * Properly update blockstore state * Error message fix again * blockchain: ignore peer missing blocks * Added FIXME * Added test for block replay with truncated history * Handle peer base in blockchain reactor * Improved replay error handling * Added tests for Store.PruneBlocks() * Fix non-RPC handling of truncated block history * Panic on missing block meta in needProofBlock() * Updated changelog * Handle truncated block history in RPC layer * Added info about earliest block in /status RPC * Reorder height and base in blockchain reactor messages * Updated changelog * Fix tests * Appease linter * Minor review fixes * Non-empty BlockStores should always have base > 0 * Update code to assume base > 0 invariant * Added blockstore tests for pruning to 0 * Make sure we don't prune below the current base * Added BlockStore.Size() * config: added retain_blocks recommendations * Update v1 blockchain reactor to handle blockstore base * Added state database pruning * Propagate errors on missing validator sets * Comment tweaks * Improved error message Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * use ABCI field ResponseCommit.retain_height instead of retain-blocks config option * remove State.RetainHeight, return value instead * fix minor issues * rename pruneHeights() to pruneBlocks() * noop to fix GitHub borkage Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
4 years ago
state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
6 years ago
pubsub 2.0 (#3227) * green pubsub tests :OK: * get rid of clientToQueryMap * Subscribe and SubscribeUnbuffered * start adapting other pkgs to new pubsub * nope * rename MsgAndTags to Message * remove TagMap it does not bring any additional benefits * bring back EventSubscriber * fix test * fix data race in TestStartNextHeightCorrectly ``` Write at 0x00c0001c7418 by goroutine 796: github.com/tendermint/tendermint/consensus.TestStartNextHeightCorrectly() /go/src/github.com/tendermint/tendermint/consensus/state_test.go:1296 +0xad testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 Previous read at 0x00c0001c7418 by goroutine 858: github.com/tendermint/tendermint/consensus.(*ConsensusState).addVote() /go/src/github.com/tendermint/tendermint/consensus/state.go:1631 +0x1366 github.com/tendermint/tendermint/consensus.(*ConsensusState).tryAddVote() /go/src/github.com/tendermint/tendermint/consensus/state.go:1476 +0x8f github.com/tendermint/tendermint/consensus.(*ConsensusState).handleMsg() /go/src/github.com/tendermint/tendermint/consensus/state.go:667 +0xa1e github.com/tendermint/tendermint/consensus.(*ConsensusState).receiveRoutine() /go/src/github.com/tendermint/tendermint/consensus/state.go:628 +0x794 Goroutine 796 (running) created at: testing.(*T).Run() /usr/local/go/src/testing/testing.go:878 +0x659 testing.runTests.func1() /usr/local/go/src/testing/testing.go:1119 +0xa8 testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 testing.runTests() /usr/local/go/src/testing/testing.go:1117 +0x4ee testing.(*M).Run() /usr/local/go/src/testing/testing.go:1034 +0x2ee main.main() _testmain.go:214 +0x332 Goroutine 858 (running) created at: github.com/tendermint/tendermint/consensus.(*ConsensusState).startRoutines() /go/src/github.com/tendermint/tendermint/consensus/state.go:334 +0x221 github.com/tendermint/tendermint/consensus.startTestRound() /go/src/github.com/tendermint/tendermint/consensus/common_test.go:122 +0x63 github.com/tendermint/tendermint/consensus.TestStateFullRound1() /go/src/github.com/tendermint/tendermint/consensus/state_test.go:255 +0x397 testing.tRunner() /usr/local/go/src/testing/testing.go:827 +0x162 ``` * fixes after my own review * fix formatting * wait 100ms before kicking a subscriber out + a test for indexer_service * fixes after my second review * no timeout * add changelog entries * fix merge conflicts * fix typos after Thane's review Co-Authored-By: melekes <anton.kalyaev@gmail.com> * reformat code * rewrite indexer service in the attempt to fix failing test https://github.com/tendermint/tendermint/pull/3227/#issuecomment-462316527 * Revert "rewrite indexer service in the attempt to fix failing test" This reverts commit 0d9107a098230de7138abb1c201877c246e89ed1. * another attempt to fix indexer * fixes after Ethan's review * use unbuffered channel when indexing transactions Refs https://github.com/tendermint/tendermint/pull/3227#discussion_r258786716 * add a comment for EventBus#SubscribeUnbuffered * format code
5 years ago
state: add more tests for block validation (#3674) * Expose priv validators for use in testing * Generalize block header validation test past height 1 * Remove ineffectual assignment * Remove redundant SaveState call * Reorder comment for clarity * Use the block executor ApplyBlock function instead of implementing a stripped-down version of it * Remove commented-out code * Remove unnecessary test The required tests already appear to be implemented (implicitly) through the TestValidateBlockHeader test. * Allow for catching of specific error types during TestValidateBlockCommit * Make return error testable * Clean up and add TestValidateBlockCommit code * Fix formatting * Extract function to create a new mock test app * Update comment for clarity * Fix comment * Add skeleton code for evidence-related test * Allow for addressing priv val by address * Generalize test beyond a single validator * Generalize TestValidateBlockEvidence past first height * Reorder code to clearly separate tests and utility code * Use a common constant for stop height for testing in state/validation_test.go * Refactor errors to resemble existing conventions * Fix formatting * Extract common helper functions Having the tests littered with helper functions makes them less easily readable imho, so I've pulled them out into a separate file. This also makes it easier to see what helper functions are available during testing, so we minimize the chance of duplication when writing new tests. * Remove unused parameter * Remove unused parameters * Add field keys * Remove unused height constant * Fix typo * Fix incorrect return error * Add field keys * Use separate package for tests This refactors all of the state package's tests into a state_test package, so as to keep any usage of the state package's internal methods explicit. Any internal methods/constants used by tests are now explicitly exported in state/export_test.go * Refactor: extract helper function to make, validate, execute and commit a block * Rename state function to makeState * Remove redundant constant for number of validators * Refactor mock evidence registration into TestMain * Remove extraneous nVals variable * Replace function-level TODOs with file-level TODO and explanation * Remove extraneous comment * Fix linting issues brought up by GolangCI (pulled in from latest merge from develop)
5 years ago
  1. package state_test
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/mock"
  8. "github.com/stretchr/testify/require"
  9. abci "github.com/tendermint/tendermint/abci/types"
  10. "github.com/tendermint/tendermint/crypto"
  11. "github.com/tendermint/tendermint/crypto/ed25519"
  12. cryptoenc "github.com/tendermint/tendermint/crypto/encoding"
  13. "github.com/tendermint/tendermint/crypto/tmhash"
  14. mmock "github.com/tendermint/tendermint/internal/mempool/mock"
  15. "github.com/tendermint/tendermint/libs/log"
  16. tmtime "github.com/tendermint/tendermint/libs/time"
  17. "github.com/tendermint/tendermint/proxy"
  18. sm "github.com/tendermint/tendermint/state"
  19. "github.com/tendermint/tendermint/state/mocks"
  20. sf "github.com/tendermint/tendermint/state/test/factory"
  21. "github.com/tendermint/tendermint/store"
  22. "github.com/tendermint/tendermint/types"
  23. "github.com/tendermint/tendermint/version"
  24. dbm "github.com/tendermint/tm-db"
  25. )
  26. var (
  27. chainID = "execution_chain"
  28. testPartSize uint32 = 65536
  29. )
  30. func TestApplyBlock(t *testing.T) {
  31. app := &testApp{}
  32. cc := proxy.NewLocalClientCreator(app)
  33. proxyApp := proxy.NewAppConns(cc)
  34. err := proxyApp.Start()
  35. require.Nil(t, err)
  36. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  37. state, stateDB, _ := makeState(1, 1)
  38. stateStore := sm.NewStore(stateDB)
  39. blockStore := store.NewBlockStore(dbm.NewMemDB())
  40. blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
  41. mmock.Mempool{}, sm.EmptyEvidencePool{}, blockStore)
  42. block := sf.MakeBlock(state, 1, new(types.Commit))
  43. blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
  44. state, err = blockExec.ApplyBlock(state, blockID, block)
  45. require.Nil(t, err)
  46. // TODO check state and mempool
  47. assert.EqualValues(t, 1, state.Version.Consensus.App, "App version wasn't updated")
  48. }
  49. // TestBeginBlockValidators ensures we send absent validators list.
  50. func TestBeginBlockValidators(t *testing.T) {
  51. app := &testApp{}
  52. cc := proxy.NewLocalClientCreator(app)
  53. proxyApp := proxy.NewAppConns(cc)
  54. err := proxyApp.Start()
  55. require.Nil(t, err)
  56. defer proxyApp.Stop() //nolint:errcheck // no need to check error again
  57. state, stateDB, _ := makeState(2, 2)
  58. stateStore := sm.NewStore(stateDB)
  59. prevHash := state.LastBlockID.Hash
  60. prevParts := types.PartSetHeader{}
  61. prevBlockID := types.BlockID{Hash: prevHash, PartSetHeader: prevParts}
  62. var (
  63. now = tmtime.Now()
  64. commitSig0 = types.NewCommitSigForBlock(
  65. []byte("Signature1"),
  66. state.Validators.Validators[0].Address,
  67. now)
  68. commitSig1 = types.NewCommitSigForBlock(
  69. []byte("Signature2"),
  70. state.Validators.Validators[1].Address,
  71. now)
  72. absentSig = types.NewCommitSigAbsent()
  73. )
  74. testCases := []struct {
  75. desc string
  76. lastCommitSigs []types.CommitSig
  77. expectedAbsentValidators []int
  78. }{
  79. {"none absent", []types.CommitSig{commitSig0, commitSig1}, []int{}},
  80. {"one absent", []types.CommitSig{commitSig0, absentSig}, []int{1}},
  81. {"multiple absent", []types.CommitSig{absentSig, absentSig}, []int{0, 1}},
  82. }
  83. for _, tc := range testCases {
  84. lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs)
  85. // block for height 2
  86. block := sf.MakeBlock(state, 2, lastCommit)
  87. _, err = sm.ExecCommitBlock(nil, proxyApp.Consensus(), block, log.TestingLogger(), stateStore, 1, state)
  88. require.Nil(t, err, tc.desc)
  89. // -> app receives a list of validators with a bool indicating if they signed
  90. ctr := 0
  91. for i, v := range app.CommitVotes {
  92. if ctr < len(tc.expectedAbsentValidators) &&
  93. tc.expectedAbsentValidators[ctr] == i {
  94. assert.False(t, v.SignedLastBlock)
  95. ctr++
  96. } else {
  97. assert.True(t, v.SignedLastBlock)
  98. }
  99. }
  100. }
  101. }
  102. // TestBeginBlockByzantineValidators ensures we send byzantine validators list.
  103. func TestBeginBlockByzantineValidators(t *testing.T) {
  104. app := &testApp{}
  105. cc := proxy.NewLocalClientCreator(app)
  106. proxyApp := proxy.NewAppConns(cc)
  107. err := proxyApp.Start()
  108. require.Nil(t, err)
  109. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  110. state, stateDB, privVals := makeState(1, 1)
  111. stateStore := sm.NewStore(stateDB)
  112. defaultEvidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  113. privVal := privVals[state.Validators.Validators[0].Address.String()]
  114. blockID := makeBlockID([]byte("headerhash"), 1000, []byte("partshash"))
  115. header := &types.Header{
  116. Version: version.Consensus{Block: version.BlockProtocol, App: 1},
  117. ChainID: state.ChainID,
  118. Height: 10,
  119. Time: defaultEvidenceTime,
  120. LastBlockID: blockID,
  121. LastCommitHash: crypto.CRandBytes(tmhash.Size),
  122. DataHash: crypto.CRandBytes(tmhash.Size),
  123. ValidatorsHash: state.Validators.Hash(),
  124. NextValidatorsHash: state.Validators.Hash(),
  125. ConsensusHash: crypto.CRandBytes(tmhash.Size),
  126. AppHash: crypto.CRandBytes(tmhash.Size),
  127. LastResultsHash: crypto.CRandBytes(tmhash.Size),
  128. EvidenceHash: crypto.CRandBytes(tmhash.Size),
  129. ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
  130. }
  131. // we don't need to worry about validating the evidence as long as they pass validate basic
  132. dve := types.NewMockDuplicateVoteEvidenceWithValidator(3, defaultEvidenceTime, privVal, state.ChainID)
  133. dve.ValidatorPower = 1000
  134. lcae := &types.LightClientAttackEvidence{
  135. ConflictingBlock: &types.LightBlock{
  136. SignedHeader: &types.SignedHeader{
  137. Header: header,
  138. Commit: types.NewCommit(10, 0, makeBlockID(header.Hash(), 100, []byte("partshash")), []types.CommitSig{{
  139. BlockIDFlag: types.BlockIDFlagNil,
  140. ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
  141. Timestamp: defaultEvidenceTime,
  142. Signature: crypto.CRandBytes(types.MaxSignatureSize),
  143. }}),
  144. },
  145. ValidatorSet: state.Validators,
  146. },
  147. CommonHeight: 8,
  148. ByzantineValidators: []*types.Validator{state.Validators.Validators[0]},
  149. TotalVotingPower: 12,
  150. Timestamp: defaultEvidenceTime,
  151. }
  152. ev := []types.Evidence{dve, lcae}
  153. abciEv := []abci.Evidence{
  154. {
  155. Type: abci.EvidenceType_DUPLICATE_VOTE,
  156. Height: 3,
  157. Time: defaultEvidenceTime,
  158. Validator: types.TM2PB.Validator(state.Validators.Validators[0]),
  159. TotalVotingPower: 10,
  160. },
  161. {
  162. Type: abci.EvidenceType_LIGHT_CLIENT_ATTACK,
  163. Height: 8,
  164. Time: defaultEvidenceTime,
  165. Validator: types.TM2PB.Validator(state.Validators.Validators[0]),
  166. TotalVotingPower: 12,
  167. },
  168. }
  169. evpool := &mocks.EvidencePool{}
  170. evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return(ev, int64(100))
  171. evpool.On("Update", mock.AnythingOfType("state.State"), mock.AnythingOfType("types.EvidenceList")).Return()
  172. evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil)
  173. blockStore := store.NewBlockStore(dbm.NewMemDB())
  174. blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
  175. mmock.Mempool{}, evpool, blockStore)
  176. block := sf.MakeBlock(state, 1, new(types.Commit))
  177. block.Evidence = types.EvidenceData{Evidence: ev}
  178. block.Header.EvidenceHash = block.Evidence.Hash()
  179. blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
  180. _, err = blockExec.ApplyBlock(state, blockID, block)
  181. require.Nil(t, err)
  182. // TODO check state and mempool
  183. assert.Equal(t, abciEv, app.ByzantineValidators)
  184. }
  185. func TestValidateValidatorUpdates(t *testing.T) {
  186. pubkey1 := ed25519.GenPrivKey().PubKey()
  187. pubkey2 := ed25519.GenPrivKey().PubKey()
  188. pk1, err := cryptoenc.PubKeyToProto(pubkey1)
  189. assert.NoError(t, err)
  190. pk2, err := cryptoenc.PubKeyToProto(pubkey2)
  191. assert.NoError(t, err)
  192. defaultValidatorParams := types.ValidatorParams{PubKeyTypes: []string{types.ABCIPubKeyTypeEd25519}}
  193. testCases := []struct {
  194. name string
  195. abciUpdates []abci.ValidatorUpdate
  196. validatorParams types.ValidatorParams
  197. shouldErr bool
  198. }{
  199. {
  200. "adding a validator is OK",
  201. []abci.ValidatorUpdate{{PubKey: pk2, Power: 20}},
  202. defaultValidatorParams,
  203. false,
  204. },
  205. {
  206. "updating a validator is OK",
  207. []abci.ValidatorUpdate{{PubKey: pk1, Power: 20}},
  208. defaultValidatorParams,
  209. false,
  210. },
  211. {
  212. "removing a validator is OK",
  213. []abci.ValidatorUpdate{{PubKey: pk2, Power: 0}},
  214. defaultValidatorParams,
  215. false,
  216. },
  217. {
  218. "adding a validator with negative power results in error",
  219. []abci.ValidatorUpdate{{PubKey: pk2, Power: -100}},
  220. defaultValidatorParams,
  221. true,
  222. },
  223. }
  224. for _, tc := range testCases {
  225. tc := tc
  226. t.Run(tc.name, func(t *testing.T) {
  227. err := sm.ValidateValidatorUpdates(tc.abciUpdates, tc.validatorParams)
  228. if tc.shouldErr {
  229. assert.Error(t, err)
  230. } else {
  231. assert.NoError(t, err)
  232. }
  233. })
  234. }
  235. }
  236. func TestUpdateValidators(t *testing.T) {
  237. pubkey1 := ed25519.GenPrivKey().PubKey()
  238. val1 := types.NewValidator(pubkey1, 10)
  239. pubkey2 := ed25519.GenPrivKey().PubKey()
  240. val2 := types.NewValidator(pubkey2, 20)
  241. pk, err := cryptoenc.PubKeyToProto(pubkey1)
  242. require.NoError(t, err)
  243. pk2, err := cryptoenc.PubKeyToProto(pubkey2)
  244. require.NoError(t, err)
  245. testCases := []struct {
  246. name string
  247. currentSet *types.ValidatorSet
  248. abciUpdates []abci.ValidatorUpdate
  249. resultingSet *types.ValidatorSet
  250. shouldErr bool
  251. }{
  252. {
  253. "adding a validator is OK",
  254. types.NewValidatorSet([]*types.Validator{val1}),
  255. []abci.ValidatorUpdate{{PubKey: pk2, Power: 20}},
  256. types.NewValidatorSet([]*types.Validator{val1, val2}),
  257. false,
  258. },
  259. {
  260. "updating a validator is OK",
  261. types.NewValidatorSet([]*types.Validator{val1}),
  262. []abci.ValidatorUpdate{{PubKey: pk, Power: 20}},
  263. types.NewValidatorSet([]*types.Validator{types.NewValidator(pubkey1, 20)}),
  264. false,
  265. },
  266. {
  267. "removing a validator is OK",
  268. types.NewValidatorSet([]*types.Validator{val1, val2}),
  269. []abci.ValidatorUpdate{{PubKey: pk2, Power: 0}},
  270. types.NewValidatorSet([]*types.Validator{val1}),
  271. false,
  272. },
  273. {
  274. "removing a non-existing validator results in error",
  275. types.NewValidatorSet([]*types.Validator{val1}),
  276. []abci.ValidatorUpdate{{PubKey: pk2, Power: 0}},
  277. types.NewValidatorSet([]*types.Validator{val1}),
  278. true,
  279. },
  280. }
  281. for _, tc := range testCases {
  282. tc := tc
  283. t.Run(tc.name, func(t *testing.T) {
  284. updates, err := types.PB2TM.ValidatorUpdates(tc.abciUpdates)
  285. assert.NoError(t, err)
  286. err = tc.currentSet.UpdateWithChangeSet(updates)
  287. if tc.shouldErr {
  288. assert.Error(t, err)
  289. } else {
  290. assert.NoError(t, err)
  291. require.Equal(t, tc.resultingSet.Size(), tc.currentSet.Size())
  292. assert.Equal(t, tc.resultingSet.TotalVotingPower(), tc.currentSet.TotalVotingPower())
  293. assert.Equal(t, tc.resultingSet.Validators[0].Address, tc.currentSet.Validators[0].Address)
  294. if tc.resultingSet.Size() > 1 {
  295. assert.Equal(t, tc.resultingSet.Validators[1].Address, tc.currentSet.Validators[1].Address)
  296. }
  297. }
  298. })
  299. }
  300. }
  301. // TestEndBlockValidatorUpdates ensures we update validator set and send an event.
  302. func TestEndBlockValidatorUpdates(t *testing.T) {
  303. app := &testApp{}
  304. cc := proxy.NewLocalClientCreator(app)
  305. proxyApp := proxy.NewAppConns(cc)
  306. err := proxyApp.Start()
  307. require.Nil(t, err)
  308. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  309. state, stateDB, _ := makeState(1, 1)
  310. stateStore := sm.NewStore(stateDB)
  311. blockStore := store.NewBlockStore(dbm.NewMemDB())
  312. blockExec := sm.NewBlockExecutor(
  313. stateStore,
  314. log.TestingLogger(),
  315. proxyApp.Consensus(),
  316. mmock.Mempool{},
  317. sm.EmptyEvidencePool{},
  318. blockStore,
  319. )
  320. eventBus := types.NewEventBus()
  321. err = eventBus.Start()
  322. require.NoError(t, err)
  323. defer eventBus.Stop() //nolint:errcheck // ignore for tests
  324. blockExec.SetEventBus(eventBus)
  325. updatesSub, err := eventBus.Subscribe(
  326. context.Background(),
  327. "TestEndBlockValidatorUpdates",
  328. types.EventQueryValidatorSetUpdates,
  329. )
  330. require.NoError(t, err)
  331. block := sf.MakeBlock(state, 1, new(types.Commit))
  332. blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
  333. pubkey := ed25519.GenPrivKey().PubKey()
  334. pk, err := cryptoenc.PubKeyToProto(pubkey)
  335. require.NoError(t, err)
  336. app.ValidatorUpdates = []abci.ValidatorUpdate{
  337. {PubKey: pk, Power: 10},
  338. }
  339. state, err = blockExec.ApplyBlock(state, blockID, block)
  340. require.Nil(t, err)
  341. // test new validator was added to NextValidators
  342. if assert.Equal(t, state.Validators.Size()+1, state.NextValidators.Size()) {
  343. idx, _ := state.NextValidators.GetByAddress(pubkey.Address())
  344. if idx < 0 {
  345. t.Fatalf("can't find address %v in the set %v", pubkey.Address(), state.NextValidators)
  346. }
  347. }
  348. // test we threw an event
  349. select {
  350. case msg := <-updatesSub.Out():
  351. event, ok := msg.Data().(types.EventDataValidatorSetUpdates)
  352. require.True(t, ok, "Expected event of type EventDataValidatorSetUpdates, got %T", msg.Data())
  353. if assert.NotEmpty(t, event.ValidatorUpdates) {
  354. assert.Equal(t, pubkey, event.ValidatorUpdates[0].PubKey)
  355. assert.EqualValues(t, 10, event.ValidatorUpdates[0].VotingPower)
  356. }
  357. case <-updatesSub.Canceled():
  358. t.Fatalf("updatesSub was canceled (reason: %v)", updatesSub.Err())
  359. case <-time.After(1 * time.Second):
  360. t.Fatal("Did not receive EventValidatorSetUpdates within 1 sec.")
  361. }
  362. }
  363. // TestEndBlockValidatorUpdatesResultingInEmptySet checks that processing validator updates that
  364. // would result in empty set causes no panic, an error is raised and NextValidators is not updated
  365. func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
  366. app := &testApp{}
  367. cc := proxy.NewLocalClientCreator(app)
  368. proxyApp := proxy.NewAppConns(cc)
  369. err := proxyApp.Start()
  370. require.Nil(t, err)
  371. defer proxyApp.Stop() //nolint:errcheck // ignore for tests
  372. state, stateDB, _ := makeState(1, 1)
  373. stateStore := sm.NewStore(stateDB)
  374. blockStore := store.NewBlockStore(dbm.NewMemDB())
  375. blockExec := sm.NewBlockExecutor(
  376. stateStore,
  377. log.TestingLogger(),
  378. proxyApp.Consensus(),
  379. mmock.Mempool{},
  380. sm.EmptyEvidencePool{},
  381. blockStore,
  382. )
  383. block := sf.MakeBlock(state, 1, new(types.Commit))
  384. blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()}
  385. vp, err := cryptoenc.PubKeyToProto(state.Validators.Validators[0].PubKey)
  386. require.NoError(t, err)
  387. // Remove the only validator
  388. app.ValidatorUpdates = []abci.ValidatorUpdate{
  389. {PubKey: vp, Power: 0},
  390. }
  391. assert.NotPanics(t, func() { state, err = blockExec.ApplyBlock(state, blockID, block) })
  392. assert.NotNil(t, err)
  393. assert.NotEmpty(t, state.NextValidators.Validators)
  394. }
  395. func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID {
  396. var (
  397. h = make([]byte, tmhash.Size)
  398. psH = make([]byte, tmhash.Size)
  399. )
  400. copy(h, hash)
  401. copy(psH, partSetHash)
  402. return types.BlockID{
  403. Hash: h,
  404. PartSetHeader: types.PartSetHeader{
  405. Total: partSetSize,
  406. Hash: psH,
  407. },
  408. }
  409. }