Browse Source

tests: remove panics from test fixtures (#7522)

pull/7528/head
Sam Kleinman 2 years ago
committed by GitHub
parent
commit
569629486b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 814 additions and 857 deletions
  1. +11
    -15
      cmd/tendermint/commands/root_test.go
  2. +1
    -1
      crypto/merkle/proof_key_path_test.go
  3. +43
    -33
      crypto/xchacha20poly1305/vector_test.go
  4. +2
    -2
      internal/consensus/byzantine_test.go
  5. +193
    -220
      internal/consensus/common_test.go
  6. +37
    -34
      internal/consensus/mempool_test.go
  7. +5
    -4
      internal/consensus/reactor_test.go
  8. +9
    -1
      internal/consensus/replay.go
  9. +10
    -5
      internal/consensus/replay_stubs.go
  10. +104
    -115
      internal/consensus/replay_test.go
  11. +304
    -335
      internal/consensus/state_test.go
  12. +5
    -4
      internal/consensus/types/height_vote_set_test.go
  13. +1
    -1
      internal/consensus/wal_test.go
  14. +1
    -3
      internal/evidence/verify_test.go
  15. +6
    -7
      internal/libs/protoio/io_test.go
  16. +5
    -6
      internal/libs/protoio/writer_test.go
  17. +5
    -5
      internal/state/execution_test.go
  18. +8
    -10
      internal/state/helpers_test.go
  19. +3
    -3
      internal/state/validation_test.go
  20. +14
    -7
      internal/store/store_test.go
  21. +2
    -4
      libs/bits/bit_array_test.go
  22. +6
    -7
      libs/cli/setup_test.go
  23. +3
    -3
      node/node_test.go
  24. +2
    -2
      rpc/client/event_test.go
  25. +17
    -18
      rpc/jsonrpc/client/ws_client_test.go
  26. +10
    -6
      rpc/jsonrpc/jsonrpc_test.go
  27. +7
    -6
      test/e2e/tests/validator_test.go

+ 11
- 15
cmd/tendermint/commands/root_test.go View File

@ -18,17 +18,12 @@ import (
)
// clearConfig clears env vars, the given root dir, and resets viper.
func clearConfig(dir string) {
if err := os.Unsetenv("TMHOME"); err != nil {
panic(err)
}
if err := os.Unsetenv("TM_HOME"); err != nil {
panic(err)
}
func clearConfig(t *testing.T, dir string) {
t.Helper()
require.NoError(t, os.Unsetenv("TMHOME"))
require.NoError(t, os.Unsetenv("TM_HOME"))
require.NoError(t, os.RemoveAll(dir))
if err := os.RemoveAll(dir); err != nil {
panic(err)
}
viper.Reset()
config = cfg.DefaultConfig()
}
@ -46,8 +41,9 @@ func testRootCmd() *cobra.Command {
return rootCmd
}
func testSetup(rootDir string, args []string, env map[string]string) error {
clearConfig(rootDir)
func testSetup(t *testing.T, rootDir string, args []string, env map[string]string) error {
t.Helper()
clearConfig(t, rootDir)
rootCmd := testRootCmd()
cmd := cli.PrepareBaseCmd(rootCmd, "TM", rootDir)
@ -73,7 +69,7 @@ func TestRootHome(t *testing.T) {
for i, tc := range cases {
idxString := strconv.Itoa(i)
err := testSetup(defaultRoot, tc.args, tc.env)
err := testSetup(t, defaultRoot, tc.args, tc.env)
require.NoError(t, err, idxString)
assert.Equal(t, tc.root, config.RootDir, idxString)
@ -105,7 +101,7 @@ func TestRootFlagsEnv(t *testing.T) {
for i, tc := range cases {
idxString := strconv.Itoa(i)
err := testSetup(defaultRoot, tc.args, tc.env)
err := testSetup(t, defaultRoot, tc.args, tc.env)
require.NoError(t, err, idxString)
assert.Equal(t, tc.logLevel, config.LogLevel, idxString)
@ -134,7 +130,7 @@ func TestRootConfig(t *testing.T) {
for i, tc := range cases {
defaultRoot := t.TempDir()
idxString := strconv.Itoa(i)
clearConfig(defaultRoot)
clearConfig(t, defaultRoot)
// XXX: path must match cfg.defaultConfigPath
configFilePath := filepath.Join(defaultRoot, "config")


+ 1
- 1
crypto/merkle/proof_key_path_test.go View File

@ -28,7 +28,7 @@ func TestKeyPath(t *testing.T) {
case KeyEncodingHex:
rand.Read(keys[i])
default:
panic("Unexpected encoding")
require.Fail(t, "Unexpected encoding")
}
path = path.AppendKey(keys[i], enc)
}


+ 43
- 33
crypto/xchacha20poly1305/vector_test.go View File

@ -4,21 +4,61 @@ import (
"bytes"
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
)
func toHex(bits []byte) string {
return hex.EncodeToString(bits)
}
func fromHex(bits string) []byte {
func fromHex(bits string) ([]byte, error) {
b, err := hex.DecodeString(bits)
if err != nil {
panic(err)
return nil, err
}
return b
return b, nil
}
func check(t *testing.T, fn func(string) ([]byte, error), hex string) []byte {
t.Helper()
res, err := fn(hex)
require.NoError(t, err)
return res
}
func TestHChaCha20(t *testing.T) {
var hChaCha20Vectors = []struct {
key, nonce, keystream []byte
}{
{
check(t, fromHex, "0000000000000000000000000000000000000000000000000000000000000000"),
check(t, fromHex, "000000000000000000000000000000000000000000000000"),
check(t, fromHex, "1140704c328d1d5d0e30086cdf209dbd6a43b8f41518a11cc387b669b2ee6586"),
},
{
check(t, fromHex, "8000000000000000000000000000000000000000000000000000000000000000"),
check(t, fromHex, "000000000000000000000000000000000000000000000000"),
check(t, fromHex, "7d266a7fd808cae4c02a0a70dcbfbcc250dae65ce3eae7fc210f54cc8f77df86"),
},
{
check(t, fromHex, "0000000000000000000000000000000000000000000000000000000000000001"),
check(t, fromHex, "000000000000000000000000000000000000000000000002"),
check(t, fromHex, "e0c77ff931bb9163a5460c02ac281c2b53d792b1c43fea817e9ad275ae546963"),
},
{
check(t, fromHex, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
check(t, fromHex, "000102030405060708090a0b0c0d0e0f1011121314151617"),
check(t, fromHex, "51e3ff45a895675c4b33b46c64f4a9ace110d34df6a2ceab486372bacbd3eff6"),
},
{
check(t, fromHex, "24f11cce8a1b3d61e441561a696c1c1b7e173d084fd4812425435a8896a013dc"),
check(t, fromHex, "d9660c5900ae19ddad28d6e06e45fe5e"),
check(t, fromHex, "5966b3eec3bff1189f831f06afe4d4e3be97fa9235ec8c20d08acfbbb4e851e3"),
},
}
for i, v := range hChaCha20Vectors {
var key [32]byte
var nonce [16]byte
@ -32,36 +72,6 @@ func TestHChaCha20(t *testing.T) {
}
}
var hChaCha20Vectors = []struct {
key, nonce, keystream []byte
}{
{
fromHex("0000000000000000000000000000000000000000000000000000000000000000"),
fromHex("000000000000000000000000000000000000000000000000"),
fromHex("1140704c328d1d5d0e30086cdf209dbd6a43b8f41518a11cc387b669b2ee6586"),
},
{
fromHex("8000000000000000000000000000000000000000000000000000000000000000"),
fromHex("000000000000000000000000000000000000000000000000"),
fromHex("7d266a7fd808cae4c02a0a70dcbfbcc250dae65ce3eae7fc210f54cc8f77df86"),
},
{
fromHex("0000000000000000000000000000000000000000000000000000000000000001"),
fromHex("000000000000000000000000000000000000000000000002"),
fromHex("e0c77ff931bb9163a5460c02ac281c2b53d792b1c43fea817e9ad275ae546963"),
},
{
fromHex("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
fromHex("000102030405060708090a0b0c0d0e0f1011121314151617"),
fromHex("51e3ff45a895675c4b33b46c64f4a9ace110d34df6a2ceab486372bacbd3eff6"),
},
{
fromHex("24f11cce8a1b3d61e441561a696c1c1b7e173d084fd4812425435a8896a013dc"),
fromHex("d9660c5900ae19ddad28d6e06e45fe5e"),
fromHex("5966b3eec3bff1189f831f06afe4d4e3be97fa9235ec8c20d08acfbbb4e851e3"),
},
}
func TestVectors(t *testing.T) {
for i, v := range vectors {
if len(v.plaintext) == 0 {


+ 2
- 2
internal/consensus/byzantine_test.go View File

@ -58,8 +58,8 @@ func TestByzantinePrevoteEquivocation(t *testing.T) {
defer os.RemoveAll(thisConfig.RootDir)
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc()
ensureDir(t, path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc(t)
vals := types.TM2PB.ValidatorUpdates(state.Validators)
app.InitChain(abci.RequestInitChain{Validators: vals})


+ 193
- 220
internal/consensus/common_test.go View File

@ -73,10 +73,9 @@ func configSetup(t *testing.T) *config.Config {
return cfg
}
func ensureDir(dir string, mode os.FileMode) {
if err := tmos.EnsureDir(dir, mode); err != nil {
panic(err)
}
func ensureDir(t *testing.T, dir string, mode os.FileMode) {
t.Helper()
require.NoError(t, tmos.EnsureDir(dir, mode))
}
func ResetConfig(name string) (*config.Config, error) {
@ -147,6 +146,7 @@ func (vs *validatorStub) signVote(
// Sign vote for type/hash/header
func signVote(
ctx context.Context,
t *testing.T,
vs *validatorStub,
cfg *config.Config,
voteType tmproto.SignedMsgType,
@ -155,9 +155,7 @@ func signVote(
) *types.Vote {
v, err := vs.signVote(ctx, cfg, voteType, hash, header)
if err != nil {
panic(fmt.Errorf("failed to sign vote: %w", err))
}
require.NoError(t, err, "failed to sign vote")
vs.lastVote = v
@ -166,14 +164,16 @@ func signVote(
func signVotes(
ctx context.Context,
t *testing.T,
cfg *config.Config,
voteType tmproto.SignedMsgType,
hash []byte,
header types.PartSetHeader,
vss ...*validatorStub) []*types.Vote {
vss ...*validatorStub,
) []*types.Vote {
votes := make([]*types.Vote, len(vss))
for i, vs := range vss {
votes[i] = signVote(ctx, vs, cfg, voteType, hash, header)
votes[i] = signVote(ctx, t, vs, cfg, voteType, hash, header)
}
return votes
}
@ -196,16 +196,14 @@ func (vss ValidatorStubsByPower) Len() int {
return len(vss)
}
func sortVValidatorStubsByPower(ctx context.Context, vss []*validatorStub) []*validatorStub {
func sortVValidatorStubsByPower(ctx context.Context, t *testing.T, vss []*validatorStub) []*validatorStub {
t.Helper()
sort.Slice(vss, func(i, j int) bool {
vssi, err := vss[i].GetPubKey(ctx)
if err != nil {
panic(err)
}
require.NoError(t, err)
vssj, err := vss[j].GetPubKey(ctx)
if err != nil {
panic(err)
}
require.NoError(t, err)
if vss[i].VotingPower == vss[j].VotingPower {
return bytes.Compare(vssi.Address(), vssj.Address()) == -1
@ -237,23 +235,22 @@ func decideProposal(
height int64,
round int32,
) (proposal *types.Proposal, block *types.Block) {
t.Helper()
cs1.mtx.Lock()
block, blockParts, err := cs1.createProposalBlock()
require.NoError(t, err)
validRound := cs1.ValidRound
chainID := cs1.state.ChainID
cs1.mtx.Unlock()
if block == nil {
panic("Failed to createProposalBlock. Did you forget to add commit for previous block?")
}
require.NotNil(t, block, "Failed to createProposalBlock. Did you forget to add commit for previous block?")
// Make proposal
polRound, propBlockID := validRound, types.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()}
proposal = types.NewProposal(height, round, polRound, propBlockID)
p := proposal.ToProto()
if err := vs.SignProposal(ctx, chainID, p); err != nil {
panic(err)
}
require.NoError(t, vs.SignProposal(ctx, chainID, p))
proposal.Signature = p.Signature
@ -268,6 +265,7 @@ func addVotes(to *State, votes ...*types.Vote) {
func signAddVotes(
ctx context.Context,
t *testing.T,
cfg *config.Config,
to *State,
voteType tmproto.SignedMsgType,
@ -275,7 +273,7 @@ func signAddVotes(
header types.PartSetHeader,
vss ...*validatorStub,
) {
addVotes(to, signVotes(ctx, cfg, voteType, hash, header, vss...)...)
addVotes(to, signVotes(ctx, t, cfg, voteType, hash, header, vss...)...)
}
func validatePrevote(
@ -286,37 +284,37 @@ func validatePrevote(
privVal *validatorStub,
blockHash []byte,
) {
t.Helper()
prevotes := cs.Votes.Prevotes(round)
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
address := pubKey.Address()
var vote *types.Vote
if vote = prevotes.GetByAddress(address); vote == nil {
panic("Failed to find prevote from validator")
}
vote := prevotes.GetByAddress(address)
require.NotNil(t, vote, "Failed to find prevote from validator")
if blockHash == nil {
if vote.BlockID.Hash != nil {
panic(fmt.Sprintf("Expected prevote to be for nil, got %X", vote.BlockID.Hash))
}
require.Nil(t, vote.BlockID.Hash, "Expected prevote to be for nil, got %X", vote.BlockID.Hash)
} else {
if !bytes.Equal(vote.BlockID.Hash, blockHash) {
panic(fmt.Sprintf("Expected prevote to be for %X, got %X", blockHash, vote.BlockID.Hash))
}
require.True(t, bytes.Equal(vote.BlockID.Hash, blockHash), "Expected prevote to be for %X, got %X", blockHash, vote.BlockID.Hash)
}
}
func validateLastPrecommit(ctx context.Context, t *testing.T, cs *State, privVal *validatorStub, blockHash []byte) {
t.Helper()
votes := cs.LastCommit
pv, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
address := pv.Address()
var vote *types.Vote
if vote = votes.GetByAddress(address); vote == nil {
panic("Failed to find precommit from validator")
}
if !bytes.Equal(vote.BlockID.Hash, blockHash) {
panic(fmt.Sprintf("Expected precommit to be for %X, got %X", blockHash, vote.BlockID.Hash))
}
vote := votes.GetByAddress(address)
require.NotNil(t, vote)
require.True(t, bytes.Equal(vote.BlockID.Hash, blockHash),
"Expected precommit to be for %X, got %X", blockHash, vote.BlockID.Hash)
}
func validatePrecommit(
@ -329,42 +327,35 @@ func validatePrecommit(
votedBlockHash,
lockedBlockHash []byte,
) {
t.Helper()
precommits := cs.Votes.Precommits(thisRound)
pv, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
address := pv.Address()
var vote *types.Vote
if vote = precommits.GetByAddress(address); vote == nil {
panic("Failed to find precommit from validator")
}
vote := precommits.GetByAddress(address)
require.NotNil(t, vote, "Failed to find precommit from validator")
if votedBlockHash == nil {
if vote.BlockID.Hash != nil {
panic("Expected precommit to be for nil")
}
require.Nil(t, vote.BlockID.Hash, "Expected precommit to be for nil")
} else {
if !bytes.Equal(vote.BlockID.Hash, votedBlockHash) {
panic("Expected precommit to be for proposal block")
}
require.True(t, bytes.Equal(vote.BlockID.Hash, votedBlockHash), "Expected precommit to be for proposal block")
}
if lockedBlockHash == nil {
if cs.LockedRound != lockRound || cs.LockedBlock != nil {
panic(fmt.Sprintf(
"Expected to be locked on nil at round %d. Got locked at round %d with block %v",
lockRound,
cs.LockedRound,
cs.LockedBlock))
}
require.False(t, cs.LockedRound != lockRound || cs.LockedBlock != nil,
"Expected to be locked on nil at round %d. Got locked at round %d with block %v",
lockRound,
cs.LockedRound,
cs.LockedBlock)
} else {
if cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash) {
panic(fmt.Sprintf(
"Expected block to be locked on round %d, got %d. Got locked block %X, expected %X",
lockRound,
cs.LockedRound,
cs.LockedBlock.Hash(),
lockedBlockHash))
}
require.False(t, cs.LockedRound != lockRound || !bytes.Equal(cs.LockedBlock.Hash(), lockedBlockHash),
"Expected block to be locked on round %d, got %d. Got locked block %X, expected %X",
lockRound,
cs.LockedRound,
cs.LockedBlock.Hash(),
lockedBlockHash)
}
}
@ -408,32 +399,36 @@ func subscribeToVoter(ctx context.Context, t *testing.T, cs *State, addr []byte)
func newState(
ctx context.Context,
t *testing.T,
logger log.Logger,
state sm.State,
pv types.PrivValidator,
app abci.Application,
) (*State, error) {
) *State {
t.Helper()
cfg, err := config.ResetTestRoot("consensus_state_test")
if err != nil {
return nil, err
}
require.NoError(t, err)
return newStateWithConfig(ctx, logger, cfg, state, pv, app), nil
return newStateWithConfig(ctx, t, logger, cfg, state, pv, app)
}
func newStateWithConfig(
ctx context.Context,
t *testing.T,
logger log.Logger,
thisConfig *config.Config,
state sm.State,
pv types.PrivValidator,
app abci.Application,
) *State {
return newStateWithConfigAndBlockStore(ctx, logger, thisConfig, state, pv, app, store.NewBlockStore(dbm.NewMemDB()))
t.Helper()
return newStateWithConfigAndBlockStore(ctx, t, logger, thisConfig, state, pv, app, store.NewBlockStore(dbm.NewMemDB()))
}
func newStateWithConfigAndBlockStore(
ctx context.Context,
t *testing.T,
logger log.Logger,
thisConfig *config.Config,
state sm.State,
@ -441,6 +436,8 @@ func newStateWithConfigAndBlockStore(
app abci.Application,
blockStore *store.BlockStore,
) *State {
t.Helper()
// one for mempool, one for consensus
mtx := new(sync.Mutex)
proxyAppConnMem := abciclient.NewLocalClient(logger, mtx, app)
@ -464,9 +461,7 @@ func newStateWithConfigAndBlockStore(
// Make State
stateDB := dbm.NewMemDB()
stateStore := sm.NewStore(stateDB)
if err := stateStore.Save(state); err != nil { // for save height 1's validators info
panic(err)
}
require.NoError(t, stateStore.Save(state))
blockExec := sm.NewBlockExecutor(stateStore, logger, proxyAppConnCon, mempool, evpool, blockStore)
cs := NewState(ctx,
@ -481,17 +476,16 @@ func newStateWithConfigAndBlockStore(
cs.SetPrivValidator(ctx, pv)
eventBus := eventbus.NewDefault(logger.With("module", "events"))
err := eventBus.Start(ctx)
if err != nil {
panic(err)
}
require.NoError(t, eventBus.Start(ctx))
cs.SetEventBus(eventBus)
return cs
}
func loadPrivValidator(t *testing.T, cfg *config.Config) *privval.FilePV {
t.Helper()
privValidatorKeyFile := cfg.PrivValidator.KeyFile()
ensureDir(filepath.Dir(privValidatorKeyFile), 0700)
ensureDir(t, filepath.Dir(privValidatorKeyFile), 0700)
privValidatorStateFile := cfg.PrivValidator.StateFile()
privValidator, err := privval.LoadOrGenFilePV(privValidatorKeyFile, privValidatorStateFile)
require.NoError(t, err)
@ -505,16 +499,15 @@ func randState(
cfg *config.Config,
logger log.Logger,
nValidators int,
) (*State, []*validatorStub, error) {
) (*State, []*validatorStub) {
t.Helper()
// Get State
state, privVals := randGenesisState(ctx, t, cfg, nValidators, false, 10)
vss := make([]*validatorStub, nValidators)
cs, err := newState(ctx, logger, state, privVals[0], kvstore.NewApplication())
if err != nil {
return nil, nil, err
}
cs := newState(ctx, t, logger, state, privVals[0], kvstore.NewApplication())
for i := 0; i < nValidators; i++ {
vss[i] = newValidatorStub(privVals[i], int32(i))
@ -522,225 +515,208 @@ func randState(
// since cs1 starts at 1
incrementHeight(vss[1:]...)
return cs, vss, nil
return cs, vss
}
//-------------------------------------------------------------------------------
func ensureNoNewEvent(ch <-chan tmpubsub.Message, timeout time.Duration,
errorMessage string) {
func ensureNoNewEvent(t *testing.T, ch <-chan tmpubsub.Message, timeout time.Duration, errorMessage string) {
t.Helper()
select {
case <-time.After(timeout):
break
case <-ch:
panic(errorMessage)
t.Fatal(errorMessage)
}
}
func ensureNoNewEventOnChannel(ch <-chan tmpubsub.Message) {
ensureNoNewEvent(
func ensureNoNewEventOnChannel(t *testing.T, ch <-chan tmpubsub.Message) {
t.Helper()
ensureNoNewEvent(t,
ch,
ensureTimeout,
"We should be stuck waiting, not receiving new event on the channel")
}
func ensureNoNewRoundStep(stepCh <-chan tmpubsub.Message) {
func ensureNoNewRoundStep(t *testing.T, stepCh <-chan tmpubsub.Message) {
t.Helper()
ensureNoNewEvent(
t,
stepCh,
ensureTimeout,
"We should be stuck waiting, not receiving NewRoundStep event")
}
func ensureNoNewUnlock(unlockCh <-chan tmpubsub.Message) {
ensureNoNewEvent(
func ensureNoNewUnlock(t *testing.T, unlockCh <-chan tmpubsub.Message) {
t.Helper()
ensureNoNewEvent(t,
unlockCh,
ensureTimeout,
"We should be stuck waiting, not receiving Unlock event")
}
func ensureNoNewTimeout(stepCh <-chan tmpubsub.Message, timeout int64) {
func ensureNoNewTimeout(t *testing.T, stepCh <-chan tmpubsub.Message, timeout int64) {
t.Helper()
timeoutDuration := time.Duration(timeout*10) * time.Nanosecond
ensureNoNewEvent(
ensureNoNewEvent(t,
stepCh,
timeoutDuration,
"We should be stuck waiting, not receiving NewTimeout event")
}
func ensureNewEvent(ch <-chan tmpubsub.Message, height int64, round int32, timeout time.Duration, errorMessage string) {
func ensureNewEvent(t *testing.T, ch <-chan tmpubsub.Message, height int64, round int32, timeout time.Duration, errorMessage string) {
t.Helper()
select {
case <-time.After(timeout):
panic(errorMessage)
t.Fatal(errorMessage)
case msg := <-ch:
roundStateEvent, ok := msg.Data().(types.EventDataRoundState)
if !ok {
panic(fmt.Sprintf("expected a EventDataRoundState, got %T. Wrong subscription channel?",
msg.Data()))
}
if roundStateEvent.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, roundStateEvent.Height))
}
if roundStateEvent.Round != round {
panic(fmt.Sprintf("expected round %v, got %v", round, roundStateEvent.Round))
}
require.True(t, ok,
"expected a EventDataRoundState, got %T. Wrong subscription channel?",
msg.Data())
require.Equal(t, height, roundStateEvent.Height)
require.Equal(t, round, roundStateEvent.Round)
// TODO: We could check also for a step at this point!
}
}
func ensureNewRound(roundCh <-chan tmpubsub.Message, height int64, round int32) {
func ensureNewRound(t *testing.T, roundCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for NewRound event")
t.Fatal("Timeout expired while waiting for NewRound event")
case msg := <-roundCh:
newRoundEvent, ok := msg.Data().(types.EventDataNewRound)
if !ok {
panic(fmt.Sprintf("expected a EventDataNewRound, got %T. Wrong subscription channel?",
msg.Data()))
}
if newRoundEvent.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, newRoundEvent.Height))
}
if newRoundEvent.Round != round {
panic(fmt.Sprintf("expected round %v, got %v", round, newRoundEvent.Round))
}
require.True(t, ok, "expected a EventDataNewRound, got %T. Wrong subscription channel?",
msg.Data())
require.Equal(t, height, newRoundEvent.Height)
require.Equal(t, round, newRoundEvent.Round)
}
}
func ensureNewTimeout(timeoutCh <-chan tmpubsub.Message, height int64, round int32, timeout int64) {
func ensureNewTimeout(t *testing.T, timeoutCh <-chan tmpubsub.Message, height int64, round int32, timeout int64) {
t.Helper()
timeoutDuration := time.Duration(timeout*10) * time.Nanosecond
ensureNewEvent(timeoutCh, height, round, timeoutDuration,
ensureNewEvent(t, timeoutCh, height, round, timeoutDuration,
"Timeout expired while waiting for NewTimeout event")
}
func ensureNewProposal(proposalCh <-chan tmpubsub.Message, height int64, round int32) {
func ensureNewProposal(t *testing.T, proposalCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for NewProposal event")
t.Fatal("Timeout expired while waiting for NewProposal event")
case msg := <-proposalCh:
proposalEvent, ok := msg.Data().(types.EventDataCompleteProposal)
if !ok {
panic(fmt.Sprintf("expected a EventDataCompleteProposal, got %T. Wrong subscription channel?",
msg.Data()))
}
if proposalEvent.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, proposalEvent.Height))
}
if proposalEvent.Round != round {
panic(fmt.Sprintf("expected round %v, got %v", round, proposalEvent.Round))
}
require.True(t, ok, "expected a EventDataCompleteProposal, got %T. Wrong subscription channel?",
msg.Data())
require.Equal(t, height, proposalEvent.Height)
require.Equal(t, round, proposalEvent.Round)
}
}
func ensureNewValidBlock(validBlockCh <-chan tmpubsub.Message, height int64, round int32) {
ensureNewEvent(validBlockCh, height, round, ensureTimeout,
func ensureNewValidBlock(t *testing.T, validBlockCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
ensureNewEvent(t, validBlockCh, height, round, ensureTimeout,
"Timeout expired while waiting for NewValidBlock event")
}
func ensureNewBlock(blockCh <-chan tmpubsub.Message, height int64) {
func ensureNewBlock(t *testing.T, blockCh <-chan tmpubsub.Message, height int64) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for NewBlock event")
t.Fatal("Timeout expired while waiting for NewBlock event")
case msg := <-blockCh:
blockEvent, ok := msg.Data().(types.EventDataNewBlock)
if !ok {
panic(fmt.Sprintf("expected a EventDataNewBlock, got %T. Wrong subscription channel?",
msg.Data()))
}
if blockEvent.Block.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, blockEvent.Block.Height))
}
require.True(t, ok, "expected a EventDataNewBlock, got %T. Wrong subscription channel?",
msg.Data())
require.Equal(t, height, blockEvent.Block.Height)
}
}
func ensureNewBlockHeader(blockCh <-chan tmpubsub.Message, height int64, blockHash tmbytes.HexBytes) {
func ensureNewBlockHeader(t *testing.T, blockCh <-chan tmpubsub.Message, height int64, blockHash tmbytes.HexBytes) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for NewBlockHeader event")
t.Fatal("Timeout expired while waiting for NewBlockHeader event")
case msg := <-blockCh:
blockHeaderEvent, ok := msg.Data().(types.EventDataNewBlockHeader)
if !ok {
panic(fmt.Sprintf("expected a EventDataNewBlockHeader, got %T. Wrong subscription channel?",
msg.Data()))
}
if blockHeaderEvent.Header.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, blockHeaderEvent.Header.Height))
}
if !bytes.Equal(blockHeaderEvent.Header.Hash(), blockHash) {
panic(fmt.Sprintf("expected header %X, got %X", blockHash, blockHeaderEvent.Header.Hash()))
}
require.True(t, ok, "expected a EventDataNewBlockHeader, got %T. Wrong subscription channel?",
msg.Data())
require.Equal(t, height, blockHeaderEvent.Header.Height)
require.True(t, bytes.Equal(blockHeaderEvent.Header.Hash(), blockHash))
}
}
func ensureNewUnlock(unlockCh <-chan tmpubsub.Message, height int64, round int32) {
ensureNewEvent(unlockCh, height, round, ensureTimeout,
func ensureNewUnlock(t *testing.T, unlockCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
ensureNewEvent(t, unlockCh, height, round, ensureTimeout,
"Timeout expired while waiting for NewUnlock event")
}
func ensureProposal(proposalCh <-chan tmpubsub.Message, height int64, round int32, propID types.BlockID) {
func ensureProposal(t *testing.T, proposalCh <-chan tmpubsub.Message, height int64, round int32, propID types.BlockID) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for NewProposal event")
t.Fatal("Timeout expired while waiting for NewProposal event")
case msg := <-proposalCh:
proposalEvent, ok := msg.Data().(types.EventDataCompleteProposal)
if !ok {
panic(fmt.Sprintf("expected a EventDataCompleteProposal, got %T. Wrong subscription channel?",
msg.Data()))
}
if proposalEvent.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, proposalEvent.Height))
}
if proposalEvent.Round != round {
panic(fmt.Sprintf("expected round %v, got %v", round, proposalEvent.Round))
}
if !proposalEvent.BlockID.Equals(propID) {
panic(fmt.Sprintf("Proposed block does not match expected block (%v != %v)", proposalEvent.BlockID, propID))
}
require.True(t, ok, "expected a EventDataCompleteProposal, got %T. Wrong subscription channel?",
msg.Data())
require.Equal(t, height, proposalEvent.Height)
require.Equal(t, round, proposalEvent.Round)
require.True(t, proposalEvent.BlockID.Equals(propID),
"Proposed block does not match expected block (%v != %v)", proposalEvent.BlockID, propID)
}
}
func ensurePrecommit(voteCh <-chan tmpubsub.Message, height int64, round int32) {
ensureVote(voteCh, height, round, tmproto.PrecommitType)
func ensurePrecommit(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
ensureVote(t, voteCh, height, round, tmproto.PrecommitType)
}
func ensurePrevote(voteCh <-chan tmpubsub.Message, height int64, round int32) {
ensureVote(voteCh, height, round, tmproto.PrevoteType)
func ensurePrevote(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32) {
t.Helper()
ensureVote(t, voteCh, height, round, tmproto.PrevoteType)
}
func ensureVote(voteCh <-chan tmpubsub.Message, height int64, round int32,
voteType tmproto.SignedMsgType) {
func ensureVote(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, voteType tmproto.SignedMsgType) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for NewVote event")
t.Fatal("Timeout expired while waiting for NewVote event")
case msg := <-voteCh:
voteEvent, ok := msg.Data().(types.EventDataVote)
if !ok {
panic(fmt.Sprintf("expected a EventDataVote, got %T. Wrong subscription channel?",
msg.Data()))
}
require.True(t, ok, "expected a EventDataVote, got %T. Wrong subscription channel?",
msg.Data())
vote := voteEvent.Vote
if vote.Height != height {
panic(fmt.Sprintf("expected height %v, got %v", height, vote.Height))
}
if vote.Round != round {
panic(fmt.Sprintf("expected round %v, got %v", round, vote.Round))
}
if vote.Type != voteType {
panic(fmt.Sprintf("expected type %v, got %v", voteType, vote.Type))
}
require.Equal(t, height, vote.Height)
require.Equal(t, round, vote.Round)
require.Equal(t, voteType, vote.Type)
}
}
func ensurePrecommitTimeout(ch <-chan tmpubsub.Message) {
func ensurePrecommitTimeout(t *testing.T, ch <-chan tmpubsub.Message) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for the Precommit to Timeout")
t.Fatal("Timeout expired while waiting for the Precommit to Timeout")
case <-ch:
}
}
func ensureNewEventOnChannel(ch <-chan tmpubsub.Message) {
func ensureNewEventOnChannel(t *testing.T, ch <-chan tmpubsub.Message) {
t.Helper()
select {
case <-time.After(ensureTimeout):
panic("Timeout expired while waiting for new activity on the channel")
t.Fatal("Timeout expired while waiting for new activity on the channel")
case <-ch:
}
}
@ -761,7 +737,7 @@ func randConsensusState(
nValidators int,
testName string,
tickerFunc func() TimeoutTicker,
appFunc func() abci.Application,
appFunc func(t *testing.T) abci.Application,
configOpts ...func(*config.Config),
) ([]*State, cleanupFunc) {
@ -786,9 +762,9 @@ func randConsensusState(
opt(thisConfig)
}
ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
ensureDir(t, filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc()
app := appFunc(t)
if appCloser, ok := app.(io.Closer); ok {
closeFuncs = append(closeFuncs, appCloser.Close)
@ -798,7 +774,7 @@ func randConsensusState(
app.InitChain(abci.RequestInitChain{Validators: vals})
l := logger.With("validator", i, "module", "consensus")
css[i] = newStateWithConfigAndBlockStore(ctx, l, thisConfig, state, privVals[i], app, blockStore)
css[i] = newStateWithConfigAndBlockStore(ctx, t, l, thisConfig, state, privVals[i], app, blockStore)
css[i].SetTimeoutTicker(tickerFunc())
}
@ -815,6 +791,7 @@ func randConsensusState(
// nPeers = nValidators + nNotValidator
func randConsensusNetWithPeers(
ctx context.Context,
t *testing.T,
cfg *config.Config,
nValidators int,
nPeers int,
@ -822,6 +799,8 @@ func randConsensusNetWithPeers(
tickerFunc func() TimeoutTicker,
appFunc func(string) abci.Application,
) ([]*State, *types.GenesisDoc, *config.Config, cleanupFunc) {
t.Helper()
genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, nValidators, false, testMinPower)
css := make([]*State, nPeers)
logger := consensusLogger()
@ -831,12 +810,10 @@ func randConsensusNetWithPeers(
for i := 0; i < nPeers; i++ {
state, _ := sm.MakeGenesisState(genDoc)
thisConfig, err := ResetConfig(fmt.Sprintf("%s_%d", testName, i))
if err != nil {
panic(err)
}
require.NoError(t, err)
configRootDirs = append(configRootDirs, thisConfig.RootDir)
ensureDir(filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
ensureDir(t, filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
if i == 0 {
peer0Config = thisConfig
}
@ -845,18 +822,13 @@ func randConsensusNetWithPeers(
privVal = privVals[i]
} else {
tempKeyFile, err := os.CreateTemp("", "priv_validator_key_")
if err != nil {
panic(err)
}
require.NoError(t, err)
tempStateFile, err := os.CreateTemp("", "priv_validator_state_")
if err != nil {
panic(err)
}
require.NoError(t, err)
privVal, err = privval.GenFilePV(tempKeyFile.Name(), tempStateFile.Name(), "")
if err != nil {
panic(err)
}
require.NoError(t, err)
}
app := appFunc(path.Join(cfg.DBDir(), fmt.Sprintf("%s_%d", testName, i)))
@ -868,7 +840,7 @@ func randConsensusNetWithPeers(
app.InitChain(abci.RequestInitChain{Validators: vals})
// sm.SaveState(stateDB,state) //height 1's validatorsInfo already saved in LoadStateFromDBOrGenesisDoc above
css[i] = newStateWithConfig(ctx, logger.With("validator", i, "module", "consensus"), thisConfig, state, privVal, app)
css[i] = newStateWithConfig(ctx, t, logger.With("validator", i, "module", "consensus"), thisConfig, state, privVal, app)
css[i].SetTimeoutTicker(tickerFunc())
}
return css, genDoc, peer0Config, func() {
@ -940,15 +912,16 @@ func (m *mockTicker) Chan() <-chan timeoutInfo {
func (*mockTicker) SetLogger(log.Logger) {}
func newPersistentKVStore() abci.Application {
func newPersistentKVStore(t *testing.T) abci.Application {
t.Helper()
dir, err := os.MkdirTemp("", "persistent-kvstore")
if err != nil {
panic(err)
}
require.NoError(t, err)
return kvstore.NewPersistentKVStoreApplication(dir)
}
func newKVStore() abci.Application {
func newKVStore(_ *testing.T) abci.Application {
return kvstore.NewApplication()
}


+ 37
- 34
internal/consensus/mempool_test.go View File

@ -22,8 +22,11 @@ import (
)
// for testing
func assertMempool(txn txNotifier) mempool.Mempool {
return txn.(mempool.Mempool)
func assertMempool(t *testing.T, txn txNotifier) mempool.Mempool {
t.Helper()
mp, ok := txn.(mempool.Mempool)
require.True(t, ok)
return mp
}
func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
@ -38,18 +41,18 @@ func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
config.Consensus.CreateEmptyBlocks = false
state, privVals := randGenesisState(ctx, t, baseConfig, 1, false, 10)
cs := newStateWithConfig(ctx, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(cs.txNotifier).EnableTxsAvailable()
cs := newStateWithConfig(ctx, t, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(t, cs.txNotifier).EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlock)
startTestRound(ctx, cs, height, round)
ensureNewEventOnChannel(newBlockCh) // first block gets committed
ensureNoNewEventOnChannel(newBlockCh)
deliverTxsRange(ctx, cs, 0, 1)
ensureNewEventOnChannel(newBlockCh) // commit txs
ensureNewEventOnChannel(newBlockCh) // commit updated app hash
ensureNoNewEventOnChannel(newBlockCh)
ensureNewEventOnChannel(t, newBlockCh) // first block gets committed
ensureNoNewEventOnChannel(t, newBlockCh)
deliverTxsRange(ctx, t, cs, 0, 1)
ensureNewEventOnChannel(t, newBlockCh) // commit txs
ensureNewEventOnChannel(t, newBlockCh) // commit updated app hash
ensureNoNewEventOnChannel(t, newBlockCh)
}
func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
@ -63,16 +66,16 @@ func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
config.Consensus.CreateEmptyBlocksInterval = ensureTimeout
state, privVals := randGenesisState(ctx, t, baseConfig, 1, false, 10)
cs := newStateWithConfig(ctx, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
cs := newStateWithConfig(ctx, t, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(cs.txNotifier).EnableTxsAvailable()
assertMempool(t, cs.txNotifier).EnableTxsAvailable()
newBlockCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlock)
startTestRound(ctx, cs, cs.Height, cs.Round)
ensureNewEventOnChannel(newBlockCh) // first block gets committed
ensureNoNewEventOnChannel(newBlockCh) // then we dont make a block ...
ensureNewEventOnChannel(newBlockCh) // until the CreateEmptyBlocksInterval has passed
ensureNewEventOnChannel(t, newBlockCh) // first block gets committed
ensureNoNewEventOnChannel(t, newBlockCh) // then we dont make a block ...
ensureNewEventOnChannel(t, newBlockCh) // until the CreateEmptyBlocksInterval has passed
}
func TestMempoolProgressInHigherRound(t *testing.T) {
@ -86,8 +89,8 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
config.Consensus.CreateEmptyBlocks = false
state, privVals := randGenesisState(ctx, t, baseConfig, 1, false, 10)
cs := newStateWithConfig(ctx, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(cs.txNotifier).EnableTxsAvailable()
cs := newStateWithConfig(ctx, t, log.TestingLogger(), config, state, privVals[0], NewCounterApplication())
assertMempool(t, cs.txNotifier).EnableTxsAvailable()
height, round := cs.Height, cs.Round
newBlockCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlock)
newRoundCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewRound)
@ -103,30 +106,29 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
}
startTestRound(ctx, cs, height, round)
ensureNewRound(newRoundCh, height, round) // first round at first height
ensureNewEventOnChannel(newBlockCh) // first block gets committed
ensureNewRound(t, newRoundCh, height, round) // first round at first height
ensureNewEventOnChannel(t, newBlockCh) // first block gets committed
height++ // moving to the next height
round = 0
ensureNewRound(newRoundCh, height, round) // first round at next height
deliverTxsRange(ctx, cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
ensureNewTimeout(timeoutCh, height, round, cs.config.TimeoutPropose.Nanoseconds())
ensureNewRound(t, newRoundCh, height, round) // first round at next height
deliverTxsRange(ctx, t, cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
ensureNewTimeout(t, timeoutCh, height, round, cs.config.TimeoutPropose.Nanoseconds())
round++ // moving to the next round
ensureNewRound(newRoundCh, height, round) // wait for the next round
ensureNewEventOnChannel(newBlockCh) // now we can commit the block
round++ // moving to the next round
ensureNewRound(t, newRoundCh, height, round) // wait for the next round
ensureNewEventOnChannel(t, newBlockCh) // now we can commit the block
}
func deliverTxsRange(ctx context.Context, cs *State, start, end int) {
func deliverTxsRange(ctx context.Context, t *testing.T, cs *State, start, end int) {
t.Helper()
// Deliver some txs.
for i := start; i < end; i++ {
txBytes := make([]byte, 8)
binary.BigEndian.PutUint64(txBytes, uint64(i))
err := assertMempool(cs.txNotifier).CheckTx(ctx, txBytes, nil, mempool.TxInfo{})
if err != nil {
panic(fmt.Errorf("error after CheckTx: %w", err))
}
err := assertMempool(t, cs.txNotifier).CheckTx(ctx, txBytes, nil, mempool.TxInfo{})
require.NoError(t, err, "error after checkTx")
}
}
@ -142,6 +144,7 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) {
cs := newStateWithConfigAndBlockStore(
ctx,
t,
logger, config, state, privVals[0], NewCounterApplication(), blockStore)
err := stateStore.Save(state)
@ -149,7 +152,7 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) {
newBlockHeaderCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlockHeader)
const numTxs int64 = 3000
go deliverTxsRange(ctx, cs, 0, int(numTxs))
go deliverTxsRange(ctx, t, cs, 0, int(numTxs))
startTestRound(ctx, cs, cs.Height, cs.Round)
for n := int64(0); n < numTxs; {
@ -172,7 +175,7 @@ func TestMempoolRmBadTx(t *testing.T) {
app := NewCounterApplication()
stateStore := sm.NewStore(dbm.NewMemDB())
blockStore := store.NewBlockStore(dbm.NewMemDB())
cs := newStateWithConfigAndBlockStore(ctx, log.TestingLogger(), config, state, privVals[0], app, blockStore)
cs := newStateWithConfigAndBlockStore(ctx, t, log.TestingLogger(), config, state, privVals[0], app, blockStore)
err := stateStore.Save(state)
require.NoError(t, err)
@ -192,7 +195,7 @@ func TestMempoolRmBadTx(t *testing.T) {
// Try to send the tx through the mempool.
// CheckTx should not err, but the app should return a bad abci code
// and the tx should get removed from the pool
err := assertMempool(cs.txNotifier).CheckTx(ctx, txBytes, func(r *abci.Response) {
err := assertMempool(t, cs.txNotifier).CheckTx(ctx, txBytes, func(r *abci.Response) {
if r.GetCheckTx().Code != code.CodeTypeBadNonce {
t.Errorf("expected checktx to return bad nonce, got %v", r)
return
@ -206,7 +209,7 @@ func TestMempoolRmBadTx(t *testing.T) {
// check for the tx
for {
txs := assertMempool(cs.txNotifier).ReapMaxBytesMaxGas(int64(len(txBytes)), -1)
txs := assertMempool(t, cs.txNotifier).ReapMaxBytesMaxGas(int64(len(txBytes)), -1)
if len(txs) == 0 {
emptyMempoolCh <- struct{}{}
return


+ 5
- 4
internal/consensus/reactor_test.go View File

@ -184,7 +184,7 @@ func waitForAndValidateBlock(
require.NoError(t, validateBlock(newBlock, activeVals))
for _, tx := range txs {
require.NoError(t, assertMempool(states[j].txNotifier).CheckTx(ctx, tx, nil, mempool.TxInfo{}))
require.NoError(t, assertMempool(t, states[j].txNotifier).CheckTx(ctx, tx, nil, mempool.TxInfo{}))
}
}
@ -381,8 +381,8 @@ func TestReactorWithEvidence(t *testing.T) {
defer os.RemoveAll(thisConfig.RootDir)
ensureDir(path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc()
ensureDir(t, path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal
app := appFunc(t)
vals := types.TM2PB.ValidatorUpdates(state.Validators)
app.InitChain(abci.RequestInitChain{Validators: vals})
@ -495,7 +495,7 @@ func TestReactorCreatesBlockWhenEmptyBlocksFalse(t *testing.T) {
// send a tx
require.NoError(
t,
assertMempool(states[3].txNotifier).CheckTx(
assertMempool(t, states[3].txNotifier).CheckTx(
ctx,
[]byte{1, 2, 3},
nil,
@ -703,6 +703,7 @@ func TestReactorValidatorSetChanges(t *testing.T) {
nVals := 4
states, _, _, cleanup := randConsensusNetWithPeers(
ctx,
t,
cfg,
nVals,
nPeers,


+ 9
- 1
internal/consensus/replay.go View File

@ -422,9 +422,17 @@ func (h *Handshaker) ReplayBlocks(
if err != nil {
return nil, err
}
mockApp := newMockProxyApp(ctx, h.logger, appHash, abciResponses)
mockApp, err := newMockProxyApp(ctx, h.logger, appHash, abciResponses)
if err != nil {
return nil, err
}
h.logger.Info("Replay last block using mock app")
state, err = h.replayBlock(ctx, state, storeBlockHeight, mockApp)
if err != nil {
return nil, err
}
return state.AppHash, err
}


+ 10
- 5
internal/consensus/replay_stubs.go View File

@ -61,17 +61,22 @@ func newMockProxyApp(
logger log.Logger,
appHash []byte,
abciResponses *tmstate.ABCIResponses,
) proxy.AppConnConsensus {
) (proxy.AppConnConsensus, error) {
clientCreator := abciclient.NewLocalCreator(&mockProxyApp{
appHash: appHash,
abciResponses: abciResponses,
})
cli, _ := clientCreator(logger)
err := cli.Start(ctx)
cli, err := clientCreator(logger)
if err != nil {
panic(err)
return nil, err
}
if err = cli.Start(ctx); err != nil {
return nil, err
}
return proxy.NewAppConnConsensus(cli, proxy.NopMetrics())
return proxy.NewAppConnConsensus(cli, proxy.NopMetrics()), nil
}
type mockProxyApp struct {


+ 104
- 115
internal/consensus/replay_test.go View File

@ -64,6 +64,7 @@ func startNewStateAndWaitForBlock(ctx context.Context, t *testing.T, consensusRe
blockStore := store.NewBlockStore(dbm.NewMemDB())
cs := newStateWithConfigAndBlockStore(
ctx,
t,
logger,
consensusReplayConfig,
state,
@ -102,16 +103,17 @@ func startNewStateAndWaitForBlock(ctx context.Context, t *testing.T, consensusRe
}
}
func sendTxs(ctx context.Context, cs *State) {
func sendTxs(ctx context.Context, t *testing.T, cs *State) {
t.Helper()
for i := 0; i < 256; i++ {
select {
case <-ctx.Done():
return
default:
tx := []byte{byte(i)}
if err := assertMempool(cs.txNotifier).CheckTx(ctx, tx, nil, mempool.TxInfo{}); err != nil {
panic(err)
}
require.NoError(t, assertMempool(t, cs.txNotifier).CheckTx(ctx, tx, nil, mempool.TxInfo{}))
i++
}
}
@ -132,7 +134,7 @@ func TestWALCrash(t *testing.T) {
1},
{"many non-empty blocks",
func(stateDB dbm.DB, cs *State, ctx context.Context) {
go sendTxs(ctx, cs)
go sendTxs(ctx, t, cs)
},
3},
}
@ -168,6 +170,7 @@ LOOP:
privValidator := loadPrivValidator(t, consensusReplayConfig)
cs := newStateWithConfigAndBlockStore(
rctx,
t,
logger,
consensusReplayConfig,
state,
@ -334,6 +337,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
css, genDoc, cfg, cleanup := randConsensusNetWithPeers(
ctx,
t,
cfg,
nVals,
nPeers,
@ -361,15 +365,15 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
// start the machine
startTestRound(ctx, css[0], height, round)
incrementHeight(vss...)
ensureNewRound(newRoundCh, height, 0)
ensureNewProposal(proposalCh, height, round)
ensureNewRound(t, newRoundCh, height, 0)
ensureNewProposal(t, proposalCh, height, round)
rs := css[0].GetRoundState()
signAddVotes(ctx, sim.Config, css[0], tmproto.PrecommitType,
signAddVotes(ctx, t, sim.Config, css[0], tmproto.PrecommitType,
rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),
vss[1:nVals]...)
ensureNewRound(newRoundCh, height+1, 0)
ensureNewRound(t, newRoundCh, height+1, 0)
// HEIGHT 2
height++
@ -379,7 +383,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
valPubKey1ABCI, err := encoding.PubKeyToProto(newValidatorPubKey1)
require.NoError(t, err)
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(ctx, newValidatorTx1, nil, mempool.TxInfo{})
err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, newValidatorTx1, nil, mempool.TxInfo{})
assert.NoError(t, err)
propBlock, _, err := css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
require.NoError(t, err)
@ -398,12 +402,12 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
if err := css[0].SetProposalAndBlock(ctx, proposal, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
ensureNewProposal(proposalCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
rs = css[0].GetRoundState()
signAddVotes(ctx, sim.Config, css[0], tmproto.PrecommitType,
signAddVotes(ctx, t, sim.Config, css[0], tmproto.PrecommitType,
rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),
vss[1:nVals]...)
ensureNewRound(newRoundCh, height+1, 0)
ensureNewRound(t, newRoundCh, height+1, 0)
// HEIGHT 3
height++
@ -413,7 +417,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
updatePubKey1ABCI, err := encoding.PubKeyToProto(updateValidatorPubKey1)
require.NoError(t, err)
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
err = assertMempool(css[0].txNotifier).CheckTx(ctx, updateValidatorTx1, nil, mempool.TxInfo{})
err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, updateValidatorTx1, nil, mempool.TxInfo{})
assert.NoError(t, err)
propBlock, _, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
require.NoError(t, err)
@ -432,12 +436,12 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
if err := css[0].SetProposalAndBlock(ctx, proposal, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
ensureNewProposal(proposalCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
rs = css[0].GetRoundState()
signAddVotes(ctx, sim.Config, css[0], tmproto.PrecommitType,
signAddVotes(ctx, t, sim.Config, css[0], tmproto.PrecommitType,
rs.ProposalBlock.Hash(), rs.ProposalBlockParts.Header(),
vss[1:nVals]...)
ensureNewRound(newRoundCh, height+1, 0)
ensureNewRound(t, newRoundCh, height+1, 0)
// HEIGHT 4
height++
@ -447,14 +451,14 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
newVal2ABCI, err := encoding.PubKeyToProto(newValidatorPubKey2)
require.NoError(t, err)
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(ctx, newValidatorTx2, nil, mempool.TxInfo{})
err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, newValidatorTx2, nil, mempool.TxInfo{})
assert.NoError(t, err)
newValidatorPubKey3, err := css[nVals+2].privValidator.GetPubKey(ctx)
require.NoError(t, err)
newVal3ABCI, err := encoding.PubKeyToProto(newValidatorPubKey3)
require.NoError(t, err)
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
err = assertMempool(css[0].txNotifier).CheckTx(ctx, newValidatorTx3, nil, mempool.TxInfo{})
err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, newValidatorTx3, nil, mempool.TxInfo{})
assert.NoError(t, err)
propBlock, _, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
require.NoError(t, err)
@ -463,7 +467,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
newVss := make([]*validatorStub, nVals+1)
copy(newVss, vss[:nVals+1])
newVss = sortVValidatorStubsByPower(ctx, newVss)
newVss = sortVValidatorStubsByPower(ctx, t, newVss)
valIndexFn := func(cssIdx int) int {
for i, vs := range newVss {
@ -477,10 +481,12 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
return i
}
}
panic(fmt.Sprintf("validator css[%d] not found in newVss", cssIdx))
t.Fatalf("validator css[%d] not found in newVss", cssIdx)
return -1
}
selfIndex := valIndexFn(0)
require.NotEqual(t, -1, selfIndex)
proposal = types.NewProposal(vss[3].Height, round, -1, blockID)
p = proposal.ToProto()
@ -493,10 +499,10 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
if err := css[0].SetProposalAndBlock(ctx, proposal, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
ensureNewProposal(proposalCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
removeValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(ctx, removeValidatorTx2, nil, mempool.TxInfo{})
err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, removeValidatorTx2, nil, mempool.TxInfo{})
assert.NoError(t, err)
rs = css[0].GetRoundState()
@ -504,38 +510,41 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
if i == selfIndex {
continue
}
signAddVotes(ctx, sim.Config, css[0],
signAddVotes(ctx, t, sim.Config, css[0],
tmproto.PrecommitType, rs.ProposalBlock.Hash(),
rs.ProposalBlockParts.Header(), newVss[i])
}
ensureNewRound(newRoundCh, height+1, 0)
ensureNewRound(t, newRoundCh, height+1, 0)
// HEIGHT 5
height++
incrementHeight(vss...)
// Reflect the changes to vss[nVals] at height 3 and resort newVss.
newVssIdx := valIndexFn(nVals)
require.NotEqual(t, -1, newVssIdx)
newVss[newVssIdx].VotingPower = 25
newVss = sortVValidatorStubsByPower(ctx, newVss)
newVss = sortVValidatorStubsByPower(ctx, t, newVss)
selfIndex = valIndexFn(0)
ensureNewProposal(proposalCh, height, round)
require.NotEqual(t, -1, selfIndex)
ensureNewProposal(t, proposalCh, height, round)
rs = css[0].GetRoundState()
for i := 0; i < nVals+1; i++ {
if i == selfIndex {
continue
}
signAddVotes(ctx, sim.Config, css[0],
signAddVotes(ctx, t, sim.Config, css[0],
tmproto.PrecommitType, rs.ProposalBlock.Hash(),
rs.ProposalBlockParts.Header(), newVss[i])
}
ensureNewRound(newRoundCh, height+1, 0)
ensureNewRound(t, newRoundCh, height+1, 0)
// HEIGHT 6
height++
incrementHeight(vss...)
removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0)
err = assertMempool(css[0].txNotifier).CheckTx(ctx, removeValidatorTx3, nil, mempool.TxInfo{})
err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, removeValidatorTx3, nil, mempool.TxInfo{})
assert.NoError(t, err)
propBlock, _, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2)
require.NoError(t, err)
@ -544,9 +553,11 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()}
newVss = make([]*validatorStub, nVals+3)
copy(newVss, vss[:nVals+3])
newVss = sortVValidatorStubsByPower(ctx, newVss)
newVss = sortVValidatorStubsByPower(ctx, t, newVss)
selfIndex = valIndexFn(0)
require.NotEqual(t, -1, selfIndex)
proposal = types.NewProposal(vss[1].Height, round, -1, blockID)
p = proposal.ToProto()
if err := vss[1].SignProposal(ctx, cfg.ChainID(), p); err != nil {
@ -558,17 +569,17 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite {
if err := css[0].SetProposalAndBlock(ctx, proposal, propBlock, propBlockParts, "some peer"); err != nil {
t.Fatal(err)
}
ensureNewProposal(proposalCh, height, round)
ensureNewProposal(t, proposalCh, height, round)
rs = css[0].GetRoundState()
for i := 0; i < nVals+3; i++ {
if i == selfIndex {
continue
}
signAddVotes(ctx, sim.Config, css[0],
signAddVotes(ctx, t, sim.Config, css[0],
tmproto.PrecommitType, rs.ProposalBlock.Hash(),
rs.ProposalBlockParts.Header(), newVss[i])
}
ensureNewRound(newRoundCh, height+1, 0)
ensureNewRound(t, newRoundCh, height+1, 0)
sim.Chain = make([]*types.Block, 0)
sim.Commits = make([]*types.Commit, 0)
@ -670,7 +681,8 @@ func TestMockProxyApp(t *testing.T) {
err = proto.Unmarshal(bytes, loadedAbciRes)
require.NoError(t, err)
mock := newMockProxyApp(ctx, logger, []byte("mock_hash"), loadedAbciRes)
mock, err := newMockProxyApp(ctx, logger, []byte("mock_hash"), loadedAbciRes)
require.NoError(t, err)
abciRes := new(tmstate.ABCIResponses)
abciRes.DeliverTxs = make([]*abci.ResponseDeliverTx, len(loadedAbciRes.DeliverTxs))
@ -701,18 +713,17 @@ func TestMockProxyApp(t *testing.T) {
assert.True(t, invalidTxs == 0)
}
func tempWALWithData(data []byte) string {
func tempWALWithData(t *testing.T, data []byte) string {
t.Helper()
walFile, err := os.CreateTemp("", "wal")
if err != nil {
panic(fmt.Errorf("failed to create temp WAL file: %w", err))
}
require.NoError(t, err, "failed to create temp WAL file")
_, err = walFile.Write(data)
if err != nil {
panic(fmt.Errorf("failed to write to temp WAL file: %w", err))
}
if err := walFile.Close(); err != nil {
panic(fmt.Errorf("failed to close temp WAL file: %w", err))
}
require.NoError(t, err, "failed to write to temp WAL file")
require.NoError(t, walFile.Close(), "failed to close temp WAL file")
return walFile.Name()
}
@ -755,7 +766,7 @@ func testHandshakeReplay(
defer func() { _ = os.RemoveAll(testConfig.RootDir) }()
walBody, err := WALWithNBlocks(ctx, t, numBlocks)
require.NoError(t, err)
walFile := tempWALWithData(walBody)
walFile := tempWALWithData(t, walBody)
cfg.Consensus.SetWalFile(walFile)
privVal, err := privval.LoadFilePV(cfg.PrivValidator.KeyFile(), cfg.PrivValidator.StateFile())
@ -766,8 +777,7 @@ func testHandshakeReplay(
err = wal.Start(ctx)
require.NoError(t, err)
t.Cleanup(func() { cancel(); wal.Wait() })
chain, commits, err = makeBlockchainFromWAL(wal)
require.NoError(t, err)
chain, commits = makeBlockchainFromWAL(t, wal)
pubKey, err := privVal.GetPubKey(ctx)
require.NoError(t, err)
stateDB, genesisState, store = stateAndStore(t, cfg, pubKey, kvstore.ProtocolVersion)
@ -897,21 +907,19 @@ func buildAppStateFromChain(
mode uint,
blockStore *mockBlockStore,
) {
t.Helper()
// start a new app without handshake, play nBlocks blocks
if err := proxyApp.Start(ctx); err != nil {
panic(err)
}
require.NoError(t, proxyApp.Start(ctx))
state.Version.Consensus.App = kvstore.ProtocolVersion // simulate handshake, receive app version
validators := types.TM2PB.ValidatorUpdates(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(ctx, abci.RequestInitChain{
_, err := proxyApp.Consensus().InitChainSync(ctx, abci.RequestInitChain{
Validators: validators,
}); err != nil {
panic(err)
}
if err := stateStore.Save(state); err != nil { // save height 1's validatorsInfo
panic(err)
}
})
require.NoError(t, err)
require.NoError(t, stateStore.Save(state)) // save height 1's validatorsInfo
switch mode {
case 0:
for i := 0; i < nBlocks; i++ {
@ -930,7 +938,7 @@ func buildAppStateFromChain(
state = applyBlock(ctx, t, stateStore, mempool, evpool, state, chain[nBlocks-1], proxyApp, blockStore)
}
default:
panic(fmt.Sprintf("unknown mode %v", mode))
require.Fail(t, "unknown mode %v", mode)
}
}
@ -949,6 +957,8 @@ func buildTMStateFromChain(
mode uint,
blockStore *mockBlockStore,
) sm.State {
t.Helper()
// run the whole chain against this client to build up the tendermint state
kvstoreApp := kvstore.NewPersistentKVStoreApplication(
filepath.Join(cfg.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode)))
@ -956,20 +966,17 @@ func buildTMStateFromChain(
clientCreator := abciclient.NewLocalCreator(kvstoreApp)
proxyApp := proxy.NewAppConns(clientCreator, logger, proxy.NopMetrics())
if err := proxyApp.Start(ctx); err != nil {
panic(err)
}
require.NoError(t, proxyApp.Start(ctx))
state.Version.Consensus.App = kvstore.ProtocolVersion // simulate handshake, receive app version
validators := types.TM2PB.ValidatorUpdates(state.Validators)
if _, err := proxyApp.Consensus().InitChainSync(ctx, abci.RequestInitChain{
_, err := proxyApp.Consensus().InitChainSync(ctx, abci.RequestInitChain{
Validators: validators,
}); err != nil {
panic(err)
}
if err := stateStore.Save(state); err != nil { // save height 1's validatorsInfo
panic(err)
}
})
require.NoError(t, err)
require.NoError(t, stateStore.Save(state))
switch mode {
case 0:
// sync right up
@ -988,7 +995,7 @@ func buildTMStateFromChain(
// get the right next appHash but keep the state back
applyBlock(ctx, t, stateStore, mempool, evpool, state, chain[len(chain)-1], proxyApp, blockStore)
default:
panic(fmt.Sprintf("unknown mode %v", mode))
require.Fail(t, "unknown mode %v", mode)
}
return state
@ -1089,17 +1096,14 @@ func (app *badApp) Commit() abci.ResponseCommit {
//--------------------------
// utils for making blocks
func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
func makeBlockchainFromWAL(t *testing.T, wal WAL) ([]*types.Block, []*types.Commit) {
t.Helper()
var height int64
// Search for height marker
gr, found, err := wal.SearchForEndHeight(height, &WALSearchOptions{})
if err != nil {
return nil, nil, err
}
if !found {
return nil, nil, fmt.Errorf("wal does not contain height %d", height)
}
require.NoError(t, err)
require.True(t, found, "wal does not contain height %d", height)
defer gr.Close()
// log.Notice("Build a blockchain by reading from the WAL")
@ -1116,9 +1120,8 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
msg, err := dec.Decode()
if err == io.EOF {
break
} else if err != nil {
return nil, nil, err
}
require.NoError(t, err)
piece := readPieceFromWAL(msg)
if piece == nil {
@ -1131,25 +1134,20 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
if thisBlockParts != nil {
var pbb = new(tmproto.Block)
bz, err := io.ReadAll(thisBlockParts.GetReader())
if err != nil {
panic(err)
}
err = proto.Unmarshal(bz, pbb)
if err != nil {
panic(err)
}
require.NoError(t, err)
require.NoError(t, proto.Unmarshal(bz, pbb))
block, err := types.BlockFromProto(pbb)
if err != nil {
panic(err)
}
require.NoError(t, err)
require.Equal(t, block.Height, height+1,
"read bad block from wal. got height %d, expected %d", block.Height, height+1)
if block.Height != height+1 {
panic(fmt.Sprintf("read bad block from wal. got height %d, expected %d", block.Height, height+1))
}
commitHeight := thisBlockCommit.Height
if commitHeight != height+1 {
panic(fmt.Sprintf("commit doesnt match. got height %d, expected %d", commitHeight, height+1))
}
require.Equal(t, commitHeight, height+1,
"commit doesnt match. got height %d, expected %d", commitHeight, height+1)
blocks = append(blocks, block)
commits = append(commits, thisBlockCommit)
height++
@ -1158,9 +1156,7 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
thisBlockParts = types.NewPartSetFromHeader(*p)
case *types.Part:
_, err := thisBlockParts.AddPart(p)
if err != nil {
return nil, nil, err
}
require.NoError(t, err)
case *types.Vote:
if p.Type == tmproto.PrecommitType {
thisBlockCommit = types.NewCommit(p.Height, p.Round,
@ -1170,28 +1166,21 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
}
// grab the last block too
bz, err := io.ReadAll(thisBlockParts.GetReader())
if err != nil {
panic(err)
}
require.NoError(t, err)
var pbb = new(tmproto.Block)
err = proto.Unmarshal(bz, pbb)
if err != nil {
panic(err)
}
require.NoError(t, proto.Unmarshal(bz, pbb))
block, err := types.BlockFromProto(pbb)
if err != nil {
panic(err)
}
if block.Height != height+1 {
panic(fmt.Sprintf("read bad block from wal. got height %d, expected %d", block.Height, height+1))
}
require.NoError(t, err)
require.Equal(t, block.Height, height+1, "read bad block from wal. got height %d, expected %d", block.Height, height+1)
commitHeight := thisBlockCommit.Height
if commitHeight != height+1 {
panic(fmt.Sprintf("commit doesnt match. got height %d, expected %d", commitHeight, height+1))
}
require.Equal(t, commitHeight, height+1, "commit does not match. got height %d, expected %d", commitHeight, height+1)
blocks = append(blocks, block)
commits = append(commits, thisBlockCommit)
return blocks, commits, nil
return blocks, commits
}
func readPieceFromWAL(msg *TimedWALMessage) interface{} {


+ 304
- 335
internal/consensus/state_test.go
File diff suppressed because it is too large
View File


+ 5
- 4
internal/consensus/types/height_vote_set_test.go View File

@ -2,6 +2,7 @@ package types
import (
"context"
"log"
"os"
"testing"
@ -21,7 +22,7 @@ func TestMain(m *testing.M) {
var err error
cfg, err = config.ResetTestRoot("consensus_height_vote_set_test")
if err != nil {
panic(err)
log.Fatal(err)
}
code := m.Run()
os.RemoveAll(cfg.RootDir)
@ -71,11 +72,11 @@ func makeVoteHR(
valIndex, round int32,
privVals []types.PrivValidator,
) *types.Vote {
t.Helper()
privVal := privVals[valIndex]
pubKey, err := privVal.GetPubKey(ctx)
if err != nil {
panic(err)
}
require.NoError(t, err)
randBytes := tmrand.Bytes(tmhash.Size)


+ 1
- 1
internal/consensus/wal_test.go View File

@ -140,7 +140,7 @@ func TestWALSearchForEndHeight(t *testing.T) {
if err != nil {
t.Fatal(err)
}
walFile := tempWALWithData(walBody)
walFile := tempWALWithData(t, walBody)
wal, err := NewWAL(log.TestingLogger(), walFile)
require.NoError(t, err)


+ 1
- 3
internal/evidence/verify_test.go View File

@ -592,9 +592,7 @@ func makeVote(
vpb := v.ToProto()
err = val.SignVote(ctx, chainID, vpb)
if err != nil {
panic(err)
}
require.NoError(t, err)
v.Signature = vpb.Signature
return v
}


+ 6
- 7
internal/libs/protoio/io_test.go View File

@ -44,7 +44,8 @@ import (
"github.com/tendermint/tendermint/internal/libs/protoio"
)
func iotest(writer protoio.WriteCloser, reader protoio.ReadCloser) error {
func iotest(t *testing.T, writer protoio.WriteCloser, reader protoio.ReadCloser) error {
t.Helper()
varint := make([]byte, binary.MaxVarintLen64)
size := 1000
msgs := make([]*test.NinOptNative, size)
@ -94,9 +95,7 @@ func iotest(writer protoio.WriteCloser, reader protoio.ReadCloser) error {
}
i++
}
if i != size {
panic("not enough messages read")
}
require.NotEqual(t, size, i)
if err := reader.Close(); err != nil {
return err
}
@ -121,7 +120,7 @@ func TestVarintNormal(t *testing.T) {
buf := newBuffer()
writer := protoio.NewDelimitedWriter(buf)
reader := protoio.NewDelimitedReader(buf, 1024*1024)
err := iotest(writer, reader)
err := iotest(t, writer, reader)
require.NoError(t, err)
require.True(t, buf.closed, "did not close buffer")
}
@ -130,7 +129,7 @@ func TestVarintNoClose(t *testing.T) {
buf := bytes.NewBuffer(nil)
writer := protoio.NewDelimitedWriter(buf)
reader := protoio.NewDelimitedReader(buf, 1024*1024)
err := iotest(writer, reader)
err := iotest(t, writer, reader)
require.NoError(t, err)
}
@ -139,7 +138,7 @@ func TestVarintMaxSize(t *testing.T) {
buf := newBuffer()
writer := protoio.NewDelimitedWriter(buf)
reader := protoio.NewDelimitedReader(buf, 20)
err := iotest(writer, reader)
err := iotest(t, writer, reader)
require.Error(t, err)
}


+ 5
- 6
internal/libs/protoio/writer_test.go View File

@ -14,11 +14,10 @@ import (
"github.com/tendermint/tendermint/types"
)
func aVote() *types.Vote {
func aVote(t testing.TB) *types.Vote {
t.Helper()
var stamp, err = time.Parse(types.TimeFormat, "2017-12-25T03:00:01.234Z")
if err != nil {
panic(err)
}
require.NoError(t, err)
return &types.Vote{
Type: tmproto.SignedMsgType(byte(tmproto.PrevoteType)),
@ -58,14 +57,14 @@ var sink interface{}
func BenchmarkMarshalDelimitedWithMarshalTo(b *testing.B) {
msgs := []proto.Message{
aVote().ToProto(),
aVote(b).ToProto(),
}
benchmarkMarshalDelimited(b, msgs)
}
func BenchmarkMarshalDelimitedNoMarshalTo(b *testing.B) {
msgs := []proto.Message{
&excludedMarshalTo{aVote().ToProto()},
&excludedMarshalTo{aVote(b).ToProto()},
}
benchmarkMarshalDelimited(b, msgs)
}


+ 5
- 5
internal/state/execution_test.go View File

@ -47,7 +47,7 @@ func TestApplyBlock(t *testing.T) {
err := proxyApp.Start(ctx)
require.NoError(t, err)
state, stateDB, _ := makeState(1, 1)
state, stateDB, _ := makeState(t, 1, 1)
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp.Consensus(),
@ -78,7 +78,7 @@ func TestBeginBlockValidators(t *testing.T) {
err := proxyApp.Start(ctx)
require.NoError(t, err)
state, stateDB, _ := makeState(2, 2)
state, stateDB, _ := makeState(t, 2, 2)
stateStore := sm.NewStore(stateDB)
prevHash := state.LastBlockID.Hash
@ -144,7 +144,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
err := proxyApp.Start(ctx)
require.NoError(t, err)
state, stateDB, privVals := makeState(1, 1)
state, stateDB, privVals := makeState(t, 1, 1)
stateStore := sm.NewStore(stateDB)
defaultEvidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
@ -377,7 +377,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
err := proxyApp.Start(ctx)
require.NoError(t, err)
state, stateDB, _ := makeState(1, 1)
state, stateDB, _ := makeState(t, 1, 1)
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(dbm.NewMemDB())
@ -452,7 +452,7 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
err := proxyApp.Start(ctx)
require.NoError(t, err)
state, stateDB, _ := makeState(1, 1)
state, stateDB, _ := makeState(t, 1, 1)
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(


+ 8
- 10
internal/state/helpers_test.go View File

@ -107,7 +107,7 @@ func makeValidCommit(
return types.NewCommit(height, 0, blockID, sigs), nil
}
func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) {
func makeState(t *testing.T, nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) {
vals := make([]types.GenesisValidator, nVals)
privVals := make(map[string]types.PrivValidator, nVals)
for i := 0; i < nVals; i++ {
@ -130,16 +130,13 @@ func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValida
stateDB := dbm.NewMemDB()
stateStore := sm.NewStore(stateDB)
if err := stateStore.Save(s); err != nil {
panic(err)
}
require.NoError(t, stateStore.Save(s))
for i := 1; i < height; i++ {
s.LastBlockHeight++
s.LastValidators = s.Validators.Copy()
if err := stateStore.Save(s); err != nil {
panic(err)
}
require.NoError(t, stateStore.Save(s))
}
return s, stateDB, privVals
@ -189,6 +186,7 @@ func makeHeaderPartsResponsesValPowerChange(
state sm.State,
power int64,
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
t.Helper()
block, err := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
require.NoError(t, err)
@ -202,9 +200,8 @@ func makeHeaderPartsResponsesValPowerChange(
_, val := state.NextValidators.GetByIndex(0)
if val.VotingPower != power {
vPbPk, err := encoding.PubKeyToProto(val.PubKey)
if err != nil {
panic(err)
}
require.NoError(t, err)
abciResponses.EndBlock = &abci.ResponseEndBlock{
ValidatorUpdates: []abci.ValidatorUpdate{
{PubKey: vPbPk, Power: power},
@ -220,6 +217,7 @@ func makeHeaderPartsResponsesParams(
state sm.State,
params *types.ConsensusParams,
) (types.Header, types.BlockID, *tmstate.ABCIResponses) {
t.Helper()
block, err := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit))
require.NoError(t, err)


+ 3
- 3
internal/state/validation_test.go View File

@ -34,7 +34,7 @@ func TestValidateBlockHeader(t *testing.T) {
proxyApp := newTestApp()
require.NoError(t, proxyApp.Start(ctx))
state, stateDB, privVals := makeState(3, 1)
state, stateDB, privVals := makeState(t, 3, 1)
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
@ -125,7 +125,7 @@ func TestValidateBlockCommit(t *testing.T) {
proxyApp := newTestApp()
require.NoError(t, proxyApp.Start(ctx))
state, stateDB, privVals := makeState(1, 1)
state, stateDB, privVals := makeState(t, 1, 1)
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
@ -253,7 +253,7 @@ func TestValidateBlockEvidence(t *testing.T) {
proxyApp := newTestApp()
require.NoError(t, proxyApp.Start(ctx))
state, stateDB, privVals := makeState(4, 1)
state, stateDB, privVals := makeState(t, 4, 1)
stateStore := sm.NewStore(stateDB)
blockStore := store.NewBlockStore(dbm.NewMemDB())
defaultEvidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)


+ 14
- 7
internal/store/store_test.go View File

@ -46,18 +46,18 @@ func makeTestCommit(height int64, timestamp time.Time) *types.Commit {
commitSigs)
}
func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore, cleanupFunc) {
func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore, cleanupFunc, error) {
cfg, err := config.ResetTestRoot("blockchain_reactor_test")
if err != nil {
panic(err)
return sm.State{}, nil, nil, err
}
blockDB := dbm.NewMemDB()
state, err := sm.MakeGenesisStateFromFile(cfg.GenesisFile())
if err != nil {
panic(fmt.Errorf("error constructing state from genesis file: %w", err))
return sm.State{}, nil, nil, fmt.Errorf("error constructing state from genesis file: %w", err)
}
return state, NewBlockStore(blockDB), func() { os.RemoveAll(cfg.RootDir) }
return state, NewBlockStore(blockDB), func() { os.RemoveAll(cfg.RootDir) }, nil
}
func freshBlockStore() (*BlockStore, dbm.DB) {
@ -77,7 +77,12 @@ var (
func TestMain(m *testing.M) {
var cleanup cleanupFunc
var err error
state, _, cleanup = makeStateAndBlockStore(log.NewNopLogger())
state, _, cleanup, err = makeStateAndBlockStore(log.NewNopLogger())
if err != nil {
stdlog.Fatal(err)
}
block, err = factory.MakeBlock(state, 1, new(types.Commit))
if err != nil {
@ -97,8 +102,9 @@ func TestMain(m *testing.M) {
// TODO: This test should be simplified ...
func TestBlockStoreSaveLoadBlock(t *testing.T) {
state, bs, cleanup := makeStateAndBlockStore(log.NewNopLogger())
state, bs, cleanup, err := makeStateAndBlockStore(log.NewNopLogger())
defer cleanup()
require.NoError(t, err)
require.Equal(t, bs.Base(), int64(0), "initially the base should be zero")
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
@ -488,8 +494,9 @@ func TestLoadBlockMeta(t *testing.T) {
}
func TestBlockFetchAtHeight(t *testing.T) {
state, bs, cleanup := makeStateAndBlockStore(log.NewNopLogger())
state, bs, cleanup, err := makeStateAndBlockStore(log.NewNopLogger())
defer cleanup()
require.NoError(t, err)
require.Equal(t, bs.Height(), int64(0), "initially the height should be zero")
block, err := factory.MakeBlock(state, bs.Height()+1, new(types.Commit))
require.NoError(t, err)


+ 2
- 4
libs/bits/bit_array_test.go View File

@ -3,7 +3,6 @@ package bits
import (
"bytes"
"encoding/json"
"fmt"
"math"
"testing"
@ -149,9 +148,8 @@ func TestBytes(t *testing.T) {
bA := NewBitArray(4)
bA.SetIndex(0, true)
check := func(bA *BitArray, bz []byte) {
if !bytes.Equal(bA.Bytes(), bz) {
panic(fmt.Sprintf("Expected %X but got %X", bz, bA.Bytes()))
}
require.True(t, bytes.Equal(bA.Bytes(), bz),
"Expected %X but got %X", bz, bA.Bytes())
}
check(bA, []byte{0x01})
bA.SetIndex(3, true)


+ 6
- 7
libs/cli/setup_test.go View File

@ -54,11 +54,10 @@ func TestSetupEnv(t *testing.T) {
}
}
func tempDir() string {
func tempDir(t *testing.T) string {
t.Helper()
cdir, err := os.MkdirTemp("", "test-cli")
if err != nil {
panic(err)
}
require.NoError(t, err)
return cdir
}
@ -66,7 +65,7 @@ func TestSetupConfig(t *testing.T) {
// we pre-create two config files we can refer to in the rest of
// the test cases.
cval1 := "fubble"
conf1 := tempDir()
conf1 := tempDir(t)
err := WriteConfigVals(conf1, map[string]string{"boo": cval1})
require.NoError(t, err)
@ -125,11 +124,11 @@ func TestSetupUnmarshal(t *testing.T) {
// we pre-create two config files we can refer to in the rest of
// the test cases.
cval1, cval2 := "someone", "else"
conf1 := tempDir()
conf1 := tempDir(t)
err := WriteConfigVals(conf1, map[string]string{"name": cval1})
require.NoError(t, err)
// even with some ignored fields, should be no problem
conf2 := tempDir()
conf2 := tempDir(t)
err = WriteConfigVals(conf2, map[string]string{"name": cval2, "foo": "bar"})
require.NoError(t, err)


+ 3
- 3
node/node_test.go View File

@ -10,6 +10,7 @@ import (
"testing"
"time"
"github.com/fortytw2/leaktest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"
@ -151,6 +152,7 @@ func TestNodeSetAppVersion(t *testing.T) {
func TestNodeSetPrivValTCP(t *testing.T) {
addr := "tcp://" + testFreeAddr(t)
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -173,9 +175,7 @@ func TestNodeSetPrivValTCP(t *testing.T) {
go func() {
err := signerServer.Start(ctx)
if err != nil {
panic(err)
}
require.NoError(t, err)
}()
defer signerServer.Stop() //nolint:errcheck // ignore for tests


+ 2
- 2
rpc/client/event_test.go View File

@ -2,7 +2,6 @@ package client_test
import (
"context"
"fmt"
"testing"
"time"
@ -26,6 +25,7 @@ func MakeTxKV() ([]byte, []byte, []byte) {
}
func testTxEventsSent(ctx context.Context, t *testing.T, broadcastMethod string, c client.Client) {
t.Helper()
// make the tx
_, _, tx := MakeTxKV()
@ -43,7 +43,7 @@ func testTxEventsSent(ctx context.Context, t *testing.T, broadcastMethod string,
case "sync":
txres, err = c.BroadcastTxSync(ctx, tx)
default:
panic(fmt.Sprintf("Unknown broadcastMethod %s", broadcastMethod))
require.FailNowf(t, "Unknown broadcastMethod %s", broadcastMethod)
}
if assert.NoError(t, err) {
assert.Equal(t, txres.Code, abci.CodeTypeOK)


+ 17
- 18
rpc/jsonrpc/client/ws_client_test.go View File

@ -20,9 +20,10 @@ import (
var wsCallTimeout = 5 * time.Second
type myHandler struct {
type myTestHandler struct {
closeConnAfterRead bool
mtx sync.RWMutex
t *testing.T
}
var upgrader = websocket.Upgrader{
@ -30,11 +31,10 @@ var upgrader = websocket.Upgrader{
WriteBufferSize: 1024,
}
func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (h *myTestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
panic(err)
}
require.NoError(h.t, err)
defer conn.Close()
for {
messageType, in, err := conn.ReadMessage()
@ -44,17 +44,16 @@ func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var req rpctypes.RPCRequest
err = json.Unmarshal(in, &req)
if err != nil {
panic(err)
}
require.NoError(h.t, err)
func() {
h.mtx.RLock()
defer h.mtx.RUnlock()
h.mtx.RLock()
if h.closeConnAfterRead {
if err := conn.Close(); err != nil {
panic(err)
if h.closeConnAfterRead {
require.NoError(h.t, conn.Close())
}
}
h.mtx.RUnlock()
}()
res := json.RawMessage(`{}`)
emptyRespBytes, _ := json.Marshal(rpctypes.RPCResponse{Result: res, ID: req.ID})
@ -68,7 +67,7 @@ func TestWSClientReconnectsAfterReadFailure(t *testing.T) {
t.Cleanup(leaktest.Check(t))
// start server
h := &myHandler{}
h := &myTestHandler{t: t}
s := httptest.NewServer(h)
defer s.Close()
@ -100,7 +99,7 @@ func TestWSClientReconnectsAfterWriteFailure(t *testing.T) {
t.Cleanup(leaktest.Check(t))
// start server
h := &myHandler{}
h := &myTestHandler{t: t}
s := httptest.NewServer(h)
defer s.Close()
@ -130,7 +129,7 @@ func TestWSClientReconnectFailure(t *testing.T) {
t.Cleanup(leaktest.Check(t))
// start server
h := &myHandler{}
h := &myTestHandler{t: t}
s := httptest.NewServer(h)
ctx, cancel := context.WithCancel(context.Background())
@ -185,7 +184,7 @@ func TestNotBlockingOnStop(t *testing.T) {
t.Cleanup(leaktest.Check(t))
timeout := 3 * time.Second
s := httptest.NewServer(&myHandler{})
s := httptest.NewServer(&myTestHandler{t: t})
defer s.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()


+ 10
- 6
rpc/jsonrpc/jsonrpc_test.go View File

@ -6,6 +6,7 @@ import (
crand "crypto/rand"
"encoding/json"
"fmt"
stdlog "log"
mrand "math/rand"
"net/http"
"os"
@ -84,22 +85,24 @@ func TestMain(m *testing.M) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
setup(ctx)
if err := setup(ctx); err != nil {
stdlog.Fatal(err.Error())
}
code := m.Run()
os.Exit(code)
}
// launch unix and tcp servers
func setup(ctx context.Context) {
func setup(ctx context.Context) error {
logger := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false)
cmd := exec.Command("rm", "-f", unixSocket)
err := cmd.Start()
if err != nil {
panic(err)
return err
}
if err = cmd.Wait(); err != nil {
panic(err)
return err
}
tcpLogger := logger.With("socket", "tcp")
@ -111,7 +114,7 @@ func setup(ctx context.Context) {
config := server.DefaultConfig()
listener1, err := server.Listen(tcpAddr, config.MaxOpenConnections)
if err != nil {
panic(err)
return err
}
go func() {
if err := server.Serve(ctx, listener1, mux, tcpLogger, config); err != nil {
@ -127,7 +130,7 @@ func setup(ctx context.Context) {
mux2.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
listener2, err := server.Listen(unixAddr, config.MaxOpenConnections)
if err != nil {
panic(err)
return err
}
go func() {
if err := server.Serve(ctx, listener2, mux2, unixLogger, config); err != nil {
@ -137,6 +140,7 @@ func setup(ctx context.Context) {
// wait for servers to start
time.Sleep(time.Second * 2)
return nil
}
func echoViaHTTP(ctx context.Context, cl client.Caller, val string) (string, error) {


+ 7
- 6
test/e2e/tests/validator_test.go View File

@ -37,7 +37,7 @@ func TestValidator_Sets(t *testing.T) {
}
valSchedule := newValidatorSchedule(*node.Testnet)
valSchedule.Increment(first - node.Testnet.InitialHeight)
require.NoError(t, valSchedule.Increment(first-node.Testnet.InitialHeight))
for h := first; h <= last; h++ {
validators := []*types.Validator{}
@ -52,7 +52,7 @@ func TestValidator_Sets(t *testing.T) {
}
require.Equal(t, valSchedule.Set.Validators, validators,
"incorrect validator set at height %v", h)
valSchedule.Increment(1)
require.NoError(t, valSchedule.Increment(1))
}
})
}
@ -80,7 +80,7 @@ func TestValidator_Propose(t *testing.T) {
proposeCount++
}
}
valSchedule.Increment(1)
require.NoError(t, valSchedule.Increment(1))
}
require.False(t, proposeCount == 0 && expectCount > 0,
@ -123,7 +123,7 @@ func TestValidator_Sign(t *testing.T) {
} else {
require.False(t, signed, "unexpected signature for block %v", block.LastCommit.Height)
}
valSchedule.Increment(1)
require.NoError(t, valSchedule.Increment(1))
}
require.False(t, signCount == 0 && expectCount > 0,
@ -154,7 +154,7 @@ func newValidatorSchedule(testnet e2e.Testnet) *validatorSchedule {
}
}
func (s *validatorSchedule) Increment(heights int64) {
func (s *validatorSchedule) Increment(heights int64) error {
for i := int64(0); i < heights; i++ {
s.height++
if s.height > 2 {
@ -162,12 +162,13 @@ func (s *validatorSchedule) Increment(heights int64) {
// two blocks after they're returned.
if update, ok := s.updates[s.height-2]; ok {
if err := s.Set.UpdateWithChangeSet(makeVals(update)); err != nil {
panic(err)
return err
}
}
}
s.Set.IncrementProposerPriority(1)
}
return nil
}
func makeVals(valMap map[*e2e.Node]int64) []*types.Validator {


Loading…
Cancel
Save