From d5c39f907dbef91c020f58be06dcfc1af5289a23 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Fri, 7 Jan 2022 15:51:39 -0500 Subject: [PATCH 01/27] test/factory: pass testing.T around rather than errors for test fixtures (#7518) --- internal/blocksync/reactor_test.go | 11 ++-- internal/consensus/byzantine_test.go | 2 +- internal/consensus/common_test.go | 6 +- internal/consensus/reactor_test.go | 2 +- internal/consensus/replay_test.go | 6 +- .../consensus/types/height_vote_set_test.go | 2 +- internal/evidence/pool_test.go | 2 +- internal/evidence/verify_test.go | 64 +++++++++---------- internal/state/helpers_test.go | 61 +++++++++--------- internal/state/rollback_test.go | 2 +- internal/state/store_test.go | 31 +++++---- internal/state/test/factory/block.go | 26 +++++--- internal/state/validation_test.go | 20 +++--- internal/statesync/block_queue_test.go | 2 +- internal/statesync/dispatcher_test.go | 4 +- internal/statesync/reactor_test.go | 20 +++--- internal/test/factory/block.go | 20 ++---- internal/test/factory/commit.go | 23 +++---- internal/test/factory/factory_test.go | 7 +- internal/test/factory/genesis.go | 14 ++-- internal/test/factory/p2p.go | 20 +++--- internal/test/factory/tx.go | 13 ++-- internal/test/factory/validator.go | 15 +++-- internal/test/factory/vote.go | 7 +- light/client_test.go | 4 +- light/store/db/db_test.go | 17 ++--- node/node_test.go | 2 +- test/e2e/runner/evidence.go | 7 +- 28 files changed, 205 insertions(+), 205 deletions(-) diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index 245f2753e..db2d0bdf0 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -144,7 +144,6 @@ func (rts *reactorTestSuite) addNode( time.Now(), ) require.NoError(t, err) - lastCommit = types.NewCommit( vote.Height, vote.Round, @@ -206,7 +205,7 @@ func TestReactor_AbruptDisconnect(t *testing.T) { require.NoError(t, err) defer os.RemoveAll(cfg.RootDir) - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, 1, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, 1, false, 30) maxBlockHeight := int64(64) rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0) @@ -245,7 +244,7 @@ func TestReactor_SyncTime(t *testing.T) { require.NoError(t, err) defer os.RemoveAll(cfg.RootDir) - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, 1, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, 1, false, 30) maxBlockHeight := int64(101) rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0) @@ -273,7 +272,7 @@ func TestReactor_NoBlockResponse(t *testing.T) { defer os.RemoveAll(cfg.RootDir) - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, 1, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, 1, false, 30) maxBlockHeight := int64(65) rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0}, 0) @@ -325,7 +324,7 @@ func TestReactor_BadBlockStopsPeer(t *testing.T) { defer os.RemoveAll(cfg.RootDir) maxBlockHeight := int64(48) - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, 1, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, 1, false, 30) rts := setup(ctx, t, genDoc, privVals[0], []int64{maxBlockHeight, 0, 0, 0, 0}, 1000) @@ -359,7 +358,7 @@ func TestReactor_BadBlockStopsPeer(t *testing.T) { // // XXX: This causes a potential race condition. // See: https://github.com/tendermint/tendermint/issues/6005 - otherGenDoc, otherPrivVals := factory.RandGenesisDoc(ctx, cfg, 1, false, 30) + otherGenDoc, otherPrivVals := factory.RandGenesisDoc(ctx, t, cfg, 1, false, 30) newNode := rts.network.MakeNode(ctx, t, p2ptest.NodeOptions{ MaxPeers: uint16(len(rts.nodes) + 1), MaxConnected: uint16(len(rts.nodes) + 1), diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index c69c81672..b4aeaa4b9 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -41,7 +41,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { tickerFunc := newMockTickerFunc(true) appFunc := newKVStore - genDoc, privVals := factory.RandGenesisDoc(ctx, config, nValidators, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, config, nValidators, false, 30) states := make([]*State, nValidators) for i := 0; i < nValidators; i++ { diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index b3507184d..523e596d2 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -741,7 +741,7 @@ func randConsensusState( configOpts ...func(*config.Config), ) ([]*State, cleanupFunc) { - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, nValidators, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, nValidators, false, 30) css := make([]*State, nValidators) logger := consensusLogger() @@ -801,7 +801,7 @@ func randConsensusNetWithPeers( ) ([]*State, *types.GenesisDoc, *config.Config, cleanupFunc) { t.Helper() - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, nValidators, false, testMinPower) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, nValidators, false, testMinPower) css := make([]*State, nPeers) logger := consensusLogger() @@ -859,7 +859,7 @@ func randGenesisState( minPower int64, ) (sm.State, []types.PrivValidator) { - genDoc, privValidators := factory.RandGenesisDoc(ctx, cfg, numValidators, randPower, minPower) + genDoc, privValidators := factory.RandGenesisDoc(ctx, t, cfg, numValidators, randPower, minPower) s0, err := sm.MakeGenesisState(genDoc) require.NoError(t, err) return s0, privValidators diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index a717c4b8b..19f45f674 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -383,7 +383,7 @@ func TestReactorWithEvidence(t *testing.T) { tickerFunc := newMockTickerFunc(true) appFunc := newKVStore - genDoc, privVals := factory.RandGenesisDoc(ctx, cfg, n, false, 30) + genDoc, privVals := factory.RandGenesisDoc(ctx, t, cfg, n, false, 30) states := make([]*State, n) logger := consensusLogger() diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index c7f1140a8..0a01d00a9 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -1023,8 +1023,7 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) { genDoc, _ := sm.MakeGenesisDocFromFile(cfg.GenesisFile()) state.LastValidators = state.Validators.Copy() // mode = 0 for committing all the blocks - blocks, err := sf.MakeBlocks(ctx, 3, &state, privVal) - require.NoError(t, err) + blocks := sf.MakeBlocks(ctx, t, 3, &state, privVal) store.chain = blocks @@ -1287,7 +1286,8 @@ func TestHandshakeUpdatesValidators(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - val, _ := factory.RandValidator(ctx, true, 10) + val, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) vals := types.NewValidatorSet([]*types.Validator{val}) app := &initChainApp{vals: types.TM2PB.ValidatorUpdates(vals)} clientCreator := abciclient.NewLocalCreator(app) diff --git a/internal/consensus/types/height_vote_set_test.go b/internal/consensus/types/height_vote_set_test.go index f9a2f80fa..cc656ffb5 100644 --- a/internal/consensus/types/height_vote_set_test.go +++ b/internal/consensus/types/height_vote_set_test.go @@ -33,7 +33,7 @@ func TestPeerCatchupRounds(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - valSet, privVals := factory.RandValidatorSet(ctx, 10, 1) + valSet, privVals := factory.RandValidatorSet(ctx, t, 10, 1) hvs := NewHeightVoteSet(cfg.ChainID(), 1, valSet) diff --git a/internal/evidence/pool_test.go b/internal/evidence/pool_test.go index 6ba20fbce..1c994724c 100644 --- a/internal/evidence/pool_test.go +++ b/internal/evidence/pool_test.go @@ -41,7 +41,7 @@ func TestEvidencePoolBasic(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - valSet, privVals := factory.RandValidatorSet(ctx, 1, 10) + valSet, privVals := factory.RandValidatorSet(ctx, t, 1, 10) blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return( &types.BlockMeta{Header: types.Header{Time: defaultEvidenceTime}}, diff --git a/internal/evidence/verify_test.go b/internal/evidence/verify_test.go index 9d2d6ff20..723364363 100644 --- a/internal/evidence/verify_test.go +++ b/internal/evidence/verify_test.go @@ -201,17 +201,16 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - conflictingVals, conflictingPrivVals := factory.RandValidatorSet(ctx, 5, 10) + conflictingVals, conflictingPrivVals := factory.RandValidatorSet(ctx, t, 5, 10) - conflictingHeader, err := factory.MakeHeader(&types.Header{ + conflictingHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: 10, Time: defaultEvidenceTime, ValidatorsHash: conflictingVals.Hash(), }) - require.NoError(t, err) - trustedHeader, _ := factory.MakeHeader(&types.Header{ + trustedHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: 10, Time: defaultEvidenceTime, @@ -228,6 +227,7 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) { voteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals) commit, err := factory.MakeCommit(ctx, blockID, 10, 1, voteSet, conflictingPrivVals[:4], defaultEvidenceTime) require.NoError(t, err) + ev := &types.LightClientAttackEvidence{ ConflictingBlock: &types.LightBlock{ SignedHeader: &types.SignedHeader{ @@ -247,27 +247,26 @@ func TestVerifyLightClientAttack_Equivocation(t *testing.T) { trustedCommit, err := factory.MakeCommit(ctx, trustedBlockID, 10, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) + trustedSignedHeader := &types.SignedHeader{ Header: trustedHeader, Commit: trustedCommit, } // good pass -> no error - err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, conflictingVals, - defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour) - assert.NoError(t, err) + require.NoError(t, evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, conflictingVals, + defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)) // trusted and conflicting hashes are the same -> an error should be returned - err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, ev.ConflictingBlock.SignedHeader, conflictingVals, - defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour) - assert.Error(t, err) + assert.Error(t, evidence.VerifyLightClientAttack(ev, trustedSignedHeader, ev.ConflictingBlock.SignedHeader, conflictingVals, + defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)) // conflicting header has different next validators hash which should have been correctly derived from // the previous round ev.ConflictingBlock.Header.NextValidatorsHash = crypto.CRandBytes(tmhash.Size) - err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, nil, - defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour) - assert.Error(t, err) + assert.Error(t, evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, nil, + defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)) + // revert next validators hash ev.ConflictingBlock.Header.NextValidatorsHash = trustedHeader.NextValidatorsHash @@ -300,17 +299,16 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - conflictingVals, conflictingPrivVals := factory.RandValidatorSet(ctx, 5, 10) + conflictingVals, conflictingPrivVals := factory.RandValidatorSet(ctx, t, 5, 10) - conflictingHeader, err := factory.MakeHeader(&types.Header{ + conflictingHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: height, Time: defaultEvidenceTime, ValidatorsHash: conflictingVals.Hash(), }) - require.NoError(t, err) - trustedHeader, _ := factory.MakeHeader(&types.Header{ + trustedHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: height, Time: defaultEvidenceTime, @@ -327,6 +325,7 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) { voteSet := types.NewVoteSet(evidenceChainID, height, 0, tmproto.SignedMsgType(2), conflictingVals) commit, err := factory.MakeCommit(ctx, blockID, height, 0, voteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) + ev := &types.LightClientAttackEvidence{ ConflictingBlock: &types.LightBlock{ SignedHeader: &types.SignedHeader{ @@ -346,20 +345,19 @@ func TestVerifyLightClientAttack_Amnesia(t *testing.T) { trustedCommit, err := factory.MakeCommit(ctx, trustedBlockID, height, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) + trustedSignedHeader := &types.SignedHeader{ Header: trustedHeader, Commit: trustedCommit, } // good pass -> no error - err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, conflictingVals, - defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour) - assert.NoError(t, err) + require.NoError(t, evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, conflictingVals, + defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)) // trusted and conflicting hashes are the same -> an error should be returned - err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, ev.ConflictingBlock.SignedHeader, conflictingVals, - defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour) - assert.Error(t, err) + assert.Error(t, evidence.VerifyLightClientAttack(ev, trustedSignedHeader, ev.ConflictingBlock.SignedHeader, conflictingVals, + defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)) state := sm.State{ LastBlockTime: defaultEvidenceTime.Add(1 * time.Minute), @@ -496,14 +494,16 @@ func makeLunaticEvidence( totalVals, byzVals, phantomVals int, commonTime, attackTime time.Time, ) (ev *types.LightClientAttackEvidence, trusted *types.LightBlock, common *types.LightBlock) { - commonValSet, commonPrivVals := factory.RandValidatorSet(ctx, totalVals, defaultVotingPower) + t.Helper() + + commonValSet, commonPrivVals := factory.RandValidatorSet(ctx, t, totalVals, defaultVotingPower) require.Greater(t, totalVals, byzVals) // extract out the subset of byzantine validators in the common validator set byzValSet, byzPrivVals := commonValSet.Validators[:byzVals], commonPrivVals[:byzVals] - phantomValSet, phantomPrivVals := factory.RandValidatorSet(ctx, phantomVals, defaultVotingPower) + phantomValSet, phantomPrivVals := factory.RandValidatorSet(ctx, t, phantomVals, defaultVotingPower) conflictingVals := phantomValSet.Copy() require.NoError(t, conflictingVals.UpdateWithChangeSet(byzValSet)) @@ -511,31 +511,30 @@ func makeLunaticEvidence( conflictingPrivVals = orderPrivValsByValSet(ctx, t, conflictingVals, conflictingPrivVals) - commonHeader, err := factory.MakeHeader(&types.Header{ + commonHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: commonHeight, Time: commonTime, }) - require.NoError(t, err) - trustedHeader, err := factory.MakeHeader(&types.Header{ + + trustedHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: height, Time: defaultEvidenceTime, }) - require.NoError(t, err) - conflictingHeader, err := factory.MakeHeader(&types.Header{ + conflictingHeader := factory.MakeHeader(t, &types.Header{ ChainID: evidenceChainID, Height: height, Time: attackTime, ValidatorsHash: conflictingVals.Hash(), }) - require.NoError(t, err) blockID := factory.MakeBlockIDWithHash(conflictingHeader.Hash()) voteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals) commit, err := factory.MakeCommit(ctx, blockID, height, 1, voteSet, conflictingPrivVals, defaultEvidenceTime) require.NoError(t, err) + ev = &types.LightClientAttackEvidence{ ConflictingBlock: &types.LightBlock{ SignedHeader: &types.SignedHeader{ @@ -559,10 +558,11 @@ func makeLunaticEvidence( ValidatorSet: commonValSet, } trustedBlockID := factory.MakeBlockIDWithHash(trustedHeader.Hash()) - trustedVals, privVals := factory.RandValidatorSet(ctx, totalVals, defaultVotingPower) + trustedVals, privVals := factory.RandValidatorSet(ctx, t, totalVals, defaultVotingPower) trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), trustedVals) trustedCommit, err := factory.MakeCommit(ctx, trustedBlockID, height, 1, trustedVoteSet, privVals, defaultEvidenceTime) require.NoError(t, err) + trusted = &types.LightBlock{ SignedHeader: &types.SignedHeader{ Header: trustedHeader, diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 1c08775c4..c28bdc104 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -40,6 +40,7 @@ func newTestApp() proxy.AppConns { func makeAndCommitGoodBlock( ctx context.Context, + t *testing.T, state sm.State, height int64, lastCommit *types.Commit, @@ -47,64 +48,59 @@ func makeAndCommitGoodBlock( blockExec *sm.BlockExecutor, privVals map[string]types.PrivValidator, evidence []types.Evidence, -) (sm.State, types.BlockID, *types.Commit, error) { +) (sm.State, types.BlockID, *types.Commit) { + t.Helper() + // A good block passes - state, blockID, err := makeAndApplyGoodBlock(ctx, state, height, lastCommit, proposerAddr, blockExec, evidence) - if err != nil { - return state, types.BlockID{}, nil, err - } + state, blockID := makeAndApplyGoodBlock(ctx, t, state, height, lastCommit, proposerAddr, blockExec, evidence) // Simulate a lastCommit for this block from all validators for the next height - commit, err := makeValidCommit(ctx, height, blockID, state.Validators, privVals) - if err != nil { - return state, types.BlockID{}, nil, err - } - return state, blockID, commit, nil + commit := makeValidCommit(ctx, t, height, blockID, state.Validators, privVals) + + return state, blockID, commit } func makeAndApplyGoodBlock( ctx context.Context, + t *testing.T, state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte, blockExec *sm.BlockExecutor, evidence []types.Evidence, -) (sm.State, types.BlockID, error) { +) (sm.State, types.BlockID) { + t.Helper() block, _, err := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) - if err != nil { - return state, types.BlockID{}, err - } + require.NoError(t, err) - if err := blockExec.ValidateBlock(state, block); err != nil { - return state, types.BlockID{}, err - } + require.NoError(t, blockExec.ValidateBlock(state, block)) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: types.PartSetHeader{Total: 3, Hash: tmrand.Bytes(32)}} state, err = blockExec.ApplyBlock(ctx, state, blockID, block) - if err != nil { - return state, types.BlockID{}, err - } - return state, blockID, nil + require.NoError(t, err) + + return state, blockID } func makeValidCommit( ctx context.Context, + t *testing.T, height int64, blockID types.BlockID, vals *types.ValidatorSet, privVals map[string]types.PrivValidator, -) (*types.Commit, error) { +) *types.Commit { + t.Helper() sigs := make([]types.CommitSig, 0) for i := 0; i < vals.Size(); i++ { _, val := vals.GetByIndex(int32(i)) vote, err := factory.MakeVote(ctx, privVals[val.Address.String()], chainID, int32(i), height, 0, 2, blockID, time.Now()) - if err != nil { - return nil, err - } + require.NoError(t, err) sigs = append(sigs, vote.CommitSig()) } - return types.NewCommit(height, 0, blockID, sigs), nil + + return types.NewCommit(height, 0, blockID, sigs) } func makeState(t *testing.T, nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) { @@ -263,9 +259,16 @@ func makeRandomStateFromValidatorSet( } } -func makeRandomStateFromConsensusParams(ctx context.Context, consensusParams *types.ConsensusParams, - height, lastHeightConsensusParamsChanged int64) sm.State { - val, _ := factory.RandValidator(ctx, true, 10) +func makeRandomStateFromConsensusParams( + ctx context.Context, + t *testing.T, + consensusParams *types.ConsensusParams, + height, + lastHeightConsensusParamsChanged int64, +) sm.State { + t.Helper() + val, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) valSet := types.NewValidatorSet([]*types.Validator{val}) return sm.State{ LastBlockHeight: height - 1, diff --git a/internal/state/rollback_test.go b/internal/state/rollback_test.go index 056d5580c..17d8e2be8 100644 --- a/internal/state/rollback_test.go +++ b/internal/state/rollback_test.go @@ -113,7 +113,7 @@ func TestRollbackDifferentStateHeight(t *testing.T) { func setupStateStore(ctx context.Context, t *testing.T, height int64) state.Store { stateStore := state.NewStore(dbm.NewMemDB()) - valSet, _ := factory.RandValidatorSet(ctx, 5, 10) + valSet, _ := factory.RandValidatorSet(ctx, t, 5, 10) params := types.DefaultConsensusParams() params.Version.AppVersion = 10 diff --git a/internal/state/store_test.go b/internal/state/store_test.go index f3334e87c..594c25c76 100644 --- a/internal/state/store_test.go +++ b/internal/state/store_test.go @@ -32,13 +32,15 @@ func TestStoreBootstrap(t *testing.T) { stateDB := dbm.NewMemDB() stateStore := sm.NewStore(stateDB) - val, _ := factory.RandValidator(ctx, true, 10) - val2, _ := factory.RandValidator(ctx, true, 10) - val3, _ := factory.RandValidator(ctx, true, 10) + val, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) + val2, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) + val3, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) vals := types.NewValidatorSet([]*types.Validator{val, val2, val3}) bootstrapState := makeRandomStateFromValidatorSet(vals, 100, 100) - err := stateStore.Bootstrap(bootstrapState) - require.NoError(t, err) + require.NoError(t, stateStore.Bootstrap(bootstrapState)) // bootstrap should also save the previous validator _, err = stateStore.LoadValidators(99) @@ -61,17 +63,18 @@ func TestStoreLoadValidators(t *testing.T) { stateDB := dbm.NewMemDB() stateStore := sm.NewStore(stateDB) - val, _ := factory.RandValidator(ctx, true, 10) - val2, _ := factory.RandValidator(ctx, true, 10) - val3, _ := factory.RandValidator(ctx, true, 10) + val, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) + val2, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) + val3, _, err := factory.RandValidator(ctx, true, 10) + require.NoError(t, err) vals := types.NewValidatorSet([]*types.Validator{val, val2, val3}) // 1) LoadValidators loads validators using a height where they were last changed // Note that only the next validators at height h + 1 are saved - err := stateStore.Save(makeRandomStateFromValidatorSet(vals, 1, 1)) - require.NoError(t, err) - err = stateStore.Save(makeRandomStateFromValidatorSet(vals.CopyIncrementProposerPriority(1), 2, 1)) - require.NoError(t, err) + require.NoError(t, stateStore.Save(makeRandomStateFromValidatorSet(vals, 1, 1))) + require.NoError(t, stateStore.Save(makeRandomStateFromValidatorSet(vals.CopyIncrementProposerPriority(1), 2, 1))) loadedVals, err := stateStore.LoadValidators(3) require.NoError(t, err) require.Equal(t, vals.CopyIncrementProposerPriority(3), loadedVals) @@ -153,7 +156,7 @@ func TestStoreLoadConsensusParams(t *testing.T) { stateDB := dbm.NewMemDB() stateStore := sm.NewStore(stateDB) - err := stateStore.Save(makeRandomStateFromConsensusParams(ctx, types.DefaultConsensusParams(), 1, 1)) + err := stateStore.Save(makeRandomStateFromConsensusParams(ctx, t, types.DefaultConsensusParams(), 1, 1)) require.NoError(t, err) params, err := stateStore.LoadConsensusParams(1) require.NoError(t, err) @@ -163,7 +166,7 @@ func TestStoreLoadConsensusParams(t *testing.T) { // it should save a pointer to the params at height 1 differentParams := types.DefaultConsensusParams() differentParams.Block.MaxBytes = 20000 - err = stateStore.Save(makeRandomStateFromConsensusParams(ctx, differentParams, 10, 1)) + err = stateStore.Save(makeRandomStateFromConsensusParams(ctx, t, differentParams, 10, 1)) require.NoError(t, err) res, err := stateStore.LoadConsensusParams(10) require.NoError(t, err) diff --git a/internal/state/test/factory/block.go b/internal/state/test/factory/block.go index 744f92a2d..96dba1ec3 100644 --- a/internal/state/test/factory/block.go +++ b/internal/state/test/factory/block.go @@ -2,14 +2,18 @@ package factory import ( "context" + "testing" "time" + "github.com/stretchr/testify/require" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/test/factory" "github.com/tendermint/tendermint/types" ) -func MakeBlocks(ctx context.Context, n int, state *sm.State, privVal types.PrivValidator) ([]*types.Block, error) { +func MakeBlocks(ctx context.Context, t *testing.T, n int, state *sm.State, privVal types.PrivValidator) []*types.Block { + t.Helper() + blocks := make([]*types.Block, n) var ( @@ -21,10 +25,7 @@ func MakeBlocks(ctx context.Context, n int, state *sm.State, privVal types.PrivV for i := 0; i < n; i++ { height := int64(i + 1) - block, parts, err := makeBlockAndPartSet(ctx, *state, prevBlock, prevBlockMeta, privVal, height) - if err != nil { - return nil, err - } + block, parts := makeBlockAndPartSet(ctx, t, *state, prevBlock, prevBlockMeta, privVal, height) blocks[i] = block @@ -37,7 +38,7 @@ func MakeBlocks(ctx context.Context, n int, state *sm.State, privVal types.PrivV state.LastBlockHeight = height } - return blocks, nil + return blocks } func MakeBlock(state sm.State, height int64, c *types.Commit) (*types.Block, error) { @@ -57,24 +58,31 @@ func MakeBlock(state sm.State, height int64, c *types.Commit) (*types.Block, err func makeBlockAndPartSet( ctx context.Context, + t *testing.T, state sm.State, lastBlock *types.Block, lastBlockMeta *types.BlockMeta, privVal types.PrivValidator, height int64, -) (*types.Block, *types.PartSet, error) { +) (*types.Block, *types.PartSet) { + t.Helper() + lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) if height > 1 { - vote, _ := factory.MakeVote( + vote, err := factory.MakeVote( ctx, privVal, lastBlock.Header.ChainID, 1, lastBlock.Header.Height, 0, 2, lastBlockMeta.BlockID, time.Now()) + require.NoError(t, err) lastCommit = types.NewCommit(vote.Height, vote.Round, lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + block, partSet, err := state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + require.NoError(t, err) + + return block, partSet } diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index f07f53606..411740c37 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -103,10 +103,8 @@ func TestValidateBlockHeader(t *testing.T) { /* A good block passes */ - var err error - state, _, lastCommit, err = makeAndCommitGoodBlock(ctx, + state, _, lastCommit = makeAndCommitGoodBlock(ctx, t, state, height, lastCommit, state.Validators.GetProposer().Address, blockExec, privVals, nil) - require.NoError(t, err, "height %d", height) } nextHeight := validationTestsStopHeight @@ -158,7 +156,7 @@ func TestValidateBlockCommit(t *testing.T) { state.LastBlockID, time.Now(), ) - require.NoError(t, err, "height %d", height) + require.NoError(t, err) wrongHeightCommit := types.NewCommit( wrongHeightVote.Height, wrongHeightVote.Round, @@ -188,10 +186,10 @@ func TestValidateBlockCommit(t *testing.T) { /* A good block passes */ - var err error var blockID types.BlockID - state, blockID, lastCommit, err = makeAndCommitGoodBlock( + state, blockID, lastCommit = makeAndCommitGoodBlock( ctx, + t, state, height, lastCommit, @@ -200,7 +198,6 @@ func TestValidateBlockCommit(t *testing.T) { privVals, nil, ) - require.NoError(t, err, "height %d", height) /* wrongSigsCommit is fine except for the extra bad precommit @@ -216,8 +213,7 @@ func TestValidateBlockCommit(t *testing.T) { blockID, time.Now(), ) - require.NoError(t, err, "height %d", height) - + require.NoError(t, err) bpvPubKey, err := badPrivVal.GetPubKey(ctx) require.NoError(t, err) @@ -319,9 +315,9 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) } - var err error - state, _, lastCommit, err = makeAndCommitGoodBlock( + state, _, lastCommit = makeAndCommitGoodBlock( ctx, + t, state, height, lastCommit, @@ -330,6 +326,6 @@ func TestValidateBlockEvidence(t *testing.T) { privVals, evidence, ) - require.NoError(t, err, "height %d", height) + } } diff --git a/internal/statesync/block_queue_test.go b/internal/statesync/block_queue_test.go index 063ccdb95..2ce2b8a68 100644 --- a/internal/statesync/block_queue_test.go +++ b/internal/statesync/block_queue_test.go @@ -294,7 +294,7 @@ loop: func mockLBResp(ctx context.Context, t *testing.T, peer types.NodeID, height int64, time time.Time) lightBlockResponse { t.Helper() - vals, pv := factory.RandValidatorSet(ctx, 3, 10) + vals, pv := factory.RandValidatorSet(ctx, t, 3, 10) _, _, lb := mockLB(ctx, t, height, time, factory.MakeBlockID(), vals, pv) return lightBlockResponse{ block: lb, diff --git a/internal/statesync/dispatcher_test.go b/internal/statesync/dispatcher_test.go index 4c9ebd4e6..918c6ec9e 100644 --- a/internal/statesync/dispatcher_test.go +++ b/internal/statesync/dispatcher_test.go @@ -76,7 +76,7 @@ func TestDispatcherReturnsNoBlock(t *testing.T) { d := NewDispatcher(ch) - peer := factory.NodeID("a") + peer := factory.NodeID(t, "a") go func() { <-chans.Out @@ -99,7 +99,7 @@ func TestDispatcherTimeOutWaitingOnLightBlock(t *testing.T) { _, ch := testChannel(100) d := NewDispatcher(ch) - peer := factory.NodeID("a") + peer := factory.NodeID(t, "a") ctx, cancelFunc := context.WithTimeout(ctx, 10*time.Millisecond) defer cancelFunc() diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index a53cd3a68..8e1256c10 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -233,7 +233,7 @@ func TestReactor_Sync(t *testing.T) { defer close(closeCh) go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh, rts.blockInCh, closeCh, 0) - go graduallyAddPeers(rts.peerUpdateCh, closeCh, 1*time.Second) + go graduallyAddPeers(t, rts.peerUpdateCh, closeCh, 1*time.Second) go handleSnapshotRequests(t, rts.snapshotOutCh, rts.snapshotInCh, closeCh, []snapshot{ { Height: uint64(snapshotHeight), @@ -434,10 +434,11 @@ func TestReactor_LightBlockResponse(t *testing.T) { rts := setup(ctx, t, nil, nil, nil, 2) var height int64 = 10 - h := factory.MakeRandomHeader() + // generates a random header + h := factory.MakeHeader(t, &types.Header{}) h.Height = height blockID := factory.MakeBlockIDWithHash(h.Hash()) - vals, pv := factory.RandValidatorSet(ctx, 1, 10) + vals, pv := factory.RandValidatorSet(ctx, t, 1, 10) vote, err := factory.MakeVote(ctx, pv[0], h.ChainID, 0, h.Height, 0, 2, blockID, factory.DefaultTestTime) require.NoError(t, err) @@ -728,7 +729,7 @@ func handleLightBlockRequests( } else { switch errorCount % 3 { case 0: // send a different block - vals, pv := factory.RandValidatorSet(ctx, 3, 10) + vals, pv := factory.RandValidatorSet(ctx, t, 3, 10) _, _, lb := mockLB(ctx, t, int64(msg.Height), factory.DefaultTestTime, factory.MakeBlockID(), vals, pv) differntLB, err := lb.ToProto() require.NoError(t, err) @@ -797,7 +798,7 @@ func buildLightBlockChain(ctx context.Context, t *testing.T, fromHeight, toHeigh chain := make(map[int64]*types.LightBlock, toHeight-fromHeight) lastBlockID := factory.MakeBlockID() blockTime := startTime.Add(time.Duration(fromHeight-toHeight) * time.Minute) - vals, pv := factory.RandValidatorSet(ctx, 3, 10) + vals, pv := factory.RandValidatorSet(ctx, t, 3, 10) for height := fromHeight; height < toHeight; height++ { vals, pv, chain[height] = mockLB(ctx, t, height, blockTime, lastBlockID, vals, pv) lastBlockID = factory.MakeBlockIDWithHash(chain[height].Header.Hash()) @@ -810,14 +811,14 @@ func mockLB(ctx context.Context, t *testing.T, height int64, time time.Time, las currentVals *types.ValidatorSet, currentPrivVals []types.PrivValidator, ) (*types.ValidatorSet, []types.PrivValidator, *types.LightBlock) { t.Helper() - header, err := factory.MakeHeader(&types.Header{ + header := factory.MakeHeader(t, &types.Header{ Height: height, LastBlockID: lastBlockID, Time: time, }) header.Version.App = testAppVersion - require.NoError(t, err) - nextVals, nextPrivVals := factory.RandValidatorSet(ctx, 3, 10) + + nextVals, nextPrivVals := factory.RandValidatorSet(ctx, t, 3, 10) header.ValidatorsHash = currentVals.Hash() header.NextValidatorsHash = nextVals.Hash() header.ConsensusHash = types.DefaultConsensusParams().HashConsensusParams() @@ -837,6 +838,7 @@ func mockLB(ctx context.Context, t *testing.T, height int64, time time.Time, las // graduallyAddPeers delivers a new randomly-generated peer update on peerUpdateCh once // per interval, until closeCh is closed. Each peer update is assigned a random node ID. func graduallyAddPeers( + t *testing.T, peerUpdateCh chan p2p.PeerUpdate, closeCh chan struct{}, interval time.Duration, @@ -846,7 +848,7 @@ func graduallyAddPeers( select { case <-ticker.C: peerUpdateCh <- p2p.PeerUpdate{ - NodeID: factory.RandomNodeID(), + NodeID: factory.RandomNodeID(t), Status: p2p.PeerStatusUp, } case <-closeCh: diff --git a/internal/test/factory/block.go b/internal/test/factory/block.go index f8772f189..654572ddf 100644 --- a/internal/test/factory/block.go +++ b/internal/test/factory/block.go @@ -1,8 +1,10 @@ package factory import ( + "testing" "time" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/types" @@ -17,13 +19,6 @@ var ( DefaultTestTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) ) -func MakeVersion() version.Consensus { - return version.Consensus{ - Block: version.BlockProtocol, - App: 1, - } -} - func RandomAddress() []byte { return crypto.CRandBytes(crypto.AddressSize) } @@ -48,7 +43,8 @@ func MakeBlockIDWithHash(hash []byte) types.BlockID { // MakeHeader fills the rest of the contents of the header such that it passes // validate basic -func MakeHeader(h *types.Header) (*types.Header, error) { +func MakeHeader(t *testing.T, h *types.Header) *types.Header { + t.Helper() if h.Version.Block == 0 { h.Version.Block = version.BlockProtocol } @@ -89,13 +85,7 @@ func MakeHeader(h *types.Header) (*types.Header, error) { h.ProposerAddress = RandomAddress() } - return h, h.ValidateBasic() -} + require.NoError(t, h.ValidateBasic()) -func MakeRandomHeader() *types.Header { - h, err := MakeHeader(&types.Header{}) - if err != nil { - panic(err) - } return h } diff --git a/internal/test/factory/commit.go b/internal/test/factory/commit.go index 28b0e0b8a..1a8691855 100644 --- a/internal/test/factory/commit.go +++ b/internal/test/factory/commit.go @@ -2,7 +2,6 @@ package factory import ( "context" - "fmt" "time" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -10,12 +9,11 @@ import ( ) func MakeCommit(ctx context.Context, blockID types.BlockID, height int64, round int32, voteSet *types.VoteSet, validators []types.PrivValidator, now time.Time) (*types.Commit, error) { - // all sign for i := 0; i < len(validators); i++ { pubKey, err := validators[i].GetPubKey(ctx) if err != nil { - return nil, fmt.Errorf("can't get pubkey: %w", err) + return nil, err } vote := &types.Vote{ ValidatorAddress: pubKey.Address(), @@ -27,21 +25,16 @@ func MakeCommit(ctx context.Context, blockID types.BlockID, height int64, round Timestamp: now, } - _, err = signAddVote(ctx, validators[i], vote, voteSet) - if err != nil { + v := vote.ToProto() + + if err := validators[i].SignVote(ctx, voteSet.ChainID(), v); err != nil { + return nil, err + } + vote.Signature = v.Signature + if _, err := voteSet.AddVote(vote); err != nil { return nil, err } } return voteSet.MakeCommit(), nil } - -func signAddVote(ctx context.Context, privVal types.PrivValidator, vote *types.Vote, voteSet *types.VoteSet) (signed bool, err error) { - v := vote.ToProto() - err = privVal.SignVote(ctx, voteSet.ChainID(), v) - if err != nil { - return false, err - } - vote.Signature = v.Signature - return voteSet.AddVote(vote) -} diff --git a/internal/test/factory/factory_test.go b/internal/test/factory/factory_test.go index 07a3ef8b3..6cdc2aed9 100644 --- a/internal/test/factory/factory_test.go +++ b/internal/test/factory/factory_test.go @@ -3,16 +3,13 @@ package factory import ( "testing" - "github.com/stretchr/testify/assert" - "github.com/tendermint/tendermint/types" ) func TestMakeHeader(t *testing.T) { - _, err := MakeHeader(&types.Header{}) - assert.NoError(t, err) + MakeHeader(t, &types.Header{}) } func TestRandomNodeID(t *testing.T) { - assert.NotPanics(t, func() { RandomNodeID() }) + RandomNodeID(t) } diff --git a/internal/test/factory/genesis.go b/internal/test/factory/genesis.go index 5fbd59416..e03a7ea90 100644 --- a/internal/test/factory/genesis.go +++ b/internal/test/factory/genesis.go @@ -3,24 +3,22 @@ package factory import ( "context" "sort" + "testing" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/config" tmtime "github.com/tendermint/tendermint/libs/time" "github.com/tendermint/tendermint/types" ) -func RandGenesisDoc( - ctx context.Context, - cfg *config.Config, - numValidators int, - randPower bool, - minPower int64, -) (*types.GenesisDoc, []types.PrivValidator) { +func RandGenesisDoc(ctx context.Context, t *testing.T, cfg *config.Config, numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) { + t.Helper() validators := make([]types.GenesisValidator, numValidators) privValidators := make([]types.PrivValidator, numValidators) for i := 0; i < numValidators; i++ { - val, privVal := RandValidator(ctx, randPower, minPower) + val, privVal, err := RandValidator(ctx, randPower, minPower) + require.NoError(t, err) validators[i] = types.GenesisValidator{ PubKey: val.PubKey, Power: val.VotingPower, diff --git a/internal/test/factory/p2p.go b/internal/test/factory/p2p.go index 34c139f58..40d8eda9d 100644 --- a/internal/test/factory/p2p.go +++ b/internal/test/factory/p2p.go @@ -3,25 +3,29 @@ package factory import ( "encoding/hex" "strings" + "testing" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/rand" "github.com/tendermint/tendermint/types" ) // NodeID returns a valid NodeID based on an inputted string -func NodeID(str string) types.NodeID { +func NodeID(t *testing.T, str string) types.NodeID { + t.Helper() + id, err := types.NewNodeID(strings.Repeat(str, 2*types.NodeIDByteLength)) - if err != nil { - panic(err) - } + require.NoError(t, err) + return id } // RandomNodeID returns a randomly generated valid NodeID -func RandomNodeID() types.NodeID { +func RandomNodeID(t *testing.T) types.NodeID { + t.Helper() + id, err := types.NewNodeID(hex.EncodeToString(rand.Bytes(types.NodeIDByteLength))) - if err != nil { - panic(err) - } + require.NoError(t, err) + return id } diff --git a/internal/test/factory/tx.go b/internal/test/factory/tx.go index c97aeefc9..035308349 100644 --- a/internal/test/factory/tx.go +++ b/internal/test/factory/tx.go @@ -2,15 +2,10 @@ package factory import "github.com/tendermint/tendermint/types" -// MakeTxs is a helper function to generate mock transactions by given the block height -// and the transaction numbers. -func MakeTxs(height int64, num int) (txs []types.Tx) { - for i := 0; i < num; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) +func MakeTenTxs(height int64) []types.Tx { + txs := make([]types.Tx, 10) + for i := range txs { + txs[i] = types.Tx([]byte{byte(height), byte(i)}) } return txs } - -func MakeTenTxs(height int64) (txs []types.Tx) { - return MakeTxs(height, 10) -} diff --git a/internal/test/factory/validator.go b/internal/test/factory/validator.go index 3b4baca80..abdb263f6 100644 --- a/internal/test/factory/validator.go +++ b/internal/test/factory/validator.go @@ -5,11 +5,13 @@ import ( "fmt" "math/rand" "sort" + "testing" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/types" ) -func RandValidator(ctx context.Context, randPower bool, minPower int64) (*types.Validator, types.PrivValidator) { +func RandValidator(ctx context.Context, randPower bool, minPower int64) (*types.Validator, types.PrivValidator, error) { privVal := types.NewMockPV() votePower := minPower if randPower { @@ -18,20 +20,23 @@ func RandValidator(ctx context.Context, randPower bool, minPower int64) (*types. } pubKey, err := privVal.GetPubKey(ctx) if err != nil { - panic(fmt.Errorf("could not retrieve pubkey %w", err)) + return nil, nil, fmt.Errorf("could not retrieve public key: %w", err) } + val := types.NewValidator(pubKey, votePower) - return val, privVal + return val, privVal, err } -func RandValidatorSet(ctx context.Context, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) { +func RandValidatorSet(ctx context.Context, t *testing.T, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) { var ( valz = make([]*types.Validator, numValidators) privValidators = make([]types.PrivValidator, numValidators) ) + t.Helper() for i := 0; i < numValidators; i++ { - val, privValidator := RandValidator(ctx, false, votingPower) + val, privValidator, err := RandValidator(ctx, false, votingPower) + require.NoError(t, err) valz[i] = val privValidators[i] = privValidator } diff --git a/internal/test/factory/vote.go b/internal/test/factory/vote.go index befa723dd..fc63e8d68 100644 --- a/internal/test/factory/vote.go +++ b/internal/test/factory/vote.go @@ -23,6 +23,7 @@ func MakeVote( if err != nil { return nil, err } + v := &types.Vote{ ValidatorAddress: pubKey.Address(), ValidatorIndex: valIndex, @@ -34,10 +35,10 @@ func MakeVote( } vpb := v.ToProto() - err = val.SignVote(ctx, chainID, vpb) - if err != nil { - panic(err) + if err := val.SignVote(ctx, chainID, vpb); err != nil { + return nil, err } + v.Signature = vpb.Signature return v, nil } diff --git a/light/client_test.go b/light/client_test.go index 002bc04e2..5fc2c3a12 100644 --- a/light/client_test.go +++ b/light/client_test.go @@ -114,7 +114,7 @@ func TestClient_SequentialVerification(t *testing.T) { newKeys := genPrivKeys(4) newVals := newKeys.ToValidators(10, 1) - differentVals, _ := factory.RandValidatorSet(ctx, 10, 100) + differentVals, _ := factory.RandValidatorSet(ctx, t, 10, 100) testCases := []struct { name string @@ -942,7 +942,7 @@ func TestClient_TrustedValidatorSet(t *testing.T) { logger := log.NewTestingLogger(t) - differentVals, _ := factory.RandValidatorSet(ctx, 10, 100) + differentVals, _ := factory.RandValidatorSet(ctx, t, 10, 100) mockBadValSetNode := mockNodeFromHeadersAndVals( map[int64]*types.SignedHeader{ 1: h1, diff --git a/light/store/db/db_test.go b/light/store/db/db_test.go index 09aa97ddb..b758ea026 100644 --- a/light/store/db/db_test.go +++ b/light/store/db/db_test.go @@ -34,7 +34,7 @@ func TestLast_FirstLightBlockHeight(t *testing.T) { assert.EqualValues(t, -1, height) // 1 key - err = dbStore.SaveLightBlock(randLightBlock(ctx, int64(1))) + err = dbStore.SaveLightBlock(randLightBlock(ctx, t, int64(1))) require.NoError(t, err) height, err = dbStore.LastLightBlockHeight() @@ -58,7 +58,7 @@ func Test_SaveLightBlock(t *testing.T) { assert.Nil(t, h) // 1 key - err = dbStore.SaveLightBlock(randLightBlock(ctx, 1)) + err = dbStore.SaveLightBlock(randLightBlock(ctx, t, 1)) require.NoError(t, err) size := dbStore.Size() @@ -90,7 +90,7 @@ func Test_LightBlockBefore(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - err := dbStore.SaveLightBlock(randLightBlock(ctx, int64(2))) + err := dbStore.SaveLightBlock(randLightBlock(ctx, t, int64(2))) require.NoError(t, err) h, err := dbStore.LightBlockBefore(3) @@ -115,7 +115,7 @@ func Test_Prune(t *testing.T) { require.NoError(t, err) // One header - err = dbStore.SaveLightBlock(randLightBlock(ctx, 2)) + err = dbStore.SaveLightBlock(randLightBlock(ctx, t, 2)) require.NoError(t, err) assert.EqualValues(t, 1, dbStore.Size()) @@ -130,7 +130,7 @@ func Test_Prune(t *testing.T) { // Multiple headers for i := 1; i <= 10; i++ { - err = dbStore.SaveLightBlock(randLightBlock(ctx, int64(i))) + err = dbStore.SaveLightBlock(randLightBlock(ctx, t, int64(i))) require.NoError(t, err) } @@ -155,7 +155,7 @@ func Test_Concurrency(t *testing.T) { go func(i int64) { defer wg.Done() - err := dbStore.SaveLightBlock(randLightBlock(ctx, i)) + err := dbStore.SaveLightBlock(randLightBlock(ctx, t, i)) require.NoError(t, err) _, err = dbStore.LightBlock(i) @@ -198,8 +198,9 @@ func Test_Concurrency(t *testing.T) { wg.Wait() } -func randLightBlock(ctx context.Context, height int64) *types.LightBlock { - vals, _ := factory.RandValidatorSet(ctx, 2, 1) +func randLightBlock(ctx context.Context, t *testing.T, height int64) *types.LightBlock { + t.Helper() + vals, _ := factory.RandValidatorSet(ctx, t, 2, 1) return &types.LightBlock{ SignedHeader: &types.SignedHeader{ Header: &types.Header{ diff --git a/node/node_test.go b/node/node_test.go index 2a32f5957..4abc3aca7 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -717,7 +717,7 @@ func loadStatefromGenesis(ctx context.Context, t *testing.T) sm.State { require.NoError(t, err) require.True(t, loadedState.IsEmpty()) - genDoc, _ := factory.RandGenesisDoc(ctx, cfg, 0, false, 10) + genDoc, _ := factory.RandGenesisDoc(ctx, t, cfg, 0, false, 10) state, err := loadStateFromDBOrGenesisDocProvider( stateStore, diff --git a/test/e2e/runner/evidence.go b/test/e2e/runner/evidence.go index 3b06754ec..a81094ad7 100644 --- a/test/e2e/runner/evidence.go +++ b/test/e2e/runner/evidence.go @@ -167,6 +167,7 @@ func generateLightClientAttackEvidence( // create a commit for the forged header blockID := makeBlockID(header.Hash(), 1000, []byte("partshash")) voteSet := types.NewVoteSet(chainID, forgedHeight, 0, tmproto.SignedMsgType(2), conflictingVals) + commit, err := factory.MakeCommit(ctx, blockID, forgedHeight, 0, voteSet, pv, forgedTime) if err != nil { return nil, err @@ -204,6 +205,7 @@ func generateDuplicateVoteEvidence( if err != nil { return nil, err } + voteA, err := factory.MakeVote(ctx, privVal, chainID, valIdx, height, 0, 2, makeRandomBlockID(), time) if err != nil { return nil, err @@ -287,7 +289,10 @@ func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.Bloc } func mutateValidatorSet(ctx context.Context, privVals []types.MockPV, vals *types.ValidatorSet) ([]types.PrivValidator, *types.ValidatorSet, error) { - newVal, newPrivVal := factory.RandValidator(ctx, false, 10) + newVal, newPrivVal, err := factory.RandValidator(ctx, false, 10) + if err != nil { + return nil, nil, err + } var newVals *types.ValidatorSet if vals.Size() > 2 { From 366ab1947a192b7bd157e36bd430183eb8a07dbd Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Sat, 8 Jan 2022 08:47:26 -0800 Subject: [PATCH 02/27] Replace uses of libs/json with encoding/json. (#7534) Where possible, replace uses of the custom JSON library with the standard library. The custom library treats interface and unnamed lteral types differently, so this change avoids those even where it would probably be safe to switch them. --- internal/consensus/peer_state.go | 4 ++-- internal/consensus/state.go | 6 +++--- internal/consensus/types/height_vote_set.go | 4 ++-- internal/consensus/types/peer_round_state.go | 6 +++--- privval/file.go | 7 ++++--- privval/file_test.go | 5 +++-- types/part_set.go | 4 ++-- types/vote_set.go | 4 ++-- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/internal/consensus/peer_state.go b/internal/consensus/peer_state.go index ada4b270e..79f4f4430 100644 --- a/internal/consensus/peer_state.go +++ b/internal/consensus/peer_state.go @@ -23,8 +23,8 @@ var ( // peerStateStats holds internal statistics for a peer. type peerStateStats struct { - Votes int `json:"votes"` - BlockParts int `json:"block_parts"` + Votes int `json:"votes,string"` + BlockParts int `json:"block_parts,string"` } func (pss peerStateStats) String() string { diff --git a/internal/consensus/state.go b/internal/consensus/state.go index 363a4beae..f2f65ca52 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -3,6 +3,7 @@ package consensus import ( "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -20,7 +21,6 @@ import ( "github.com/tendermint/tendermint/internal/libs/fail" sm "github.com/tendermint/tendermint/internal/state" tmevents "github.com/tendermint/tendermint/libs/events" - tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" tmmath "github.com/tendermint/tendermint/libs/math" tmos "github.com/tendermint/tendermint/libs/os" @@ -253,14 +253,14 @@ func (cs *State) GetRoundState() *cstypes.RoundState { func (cs *State) GetRoundStateJSON() ([]byte, error) { cs.mtx.RLock() defer cs.mtx.RUnlock() - return tmjson.Marshal(cs.RoundState) + return json.Marshal(cs.RoundState) } // GetRoundStateSimpleJSON returns a json of RoundStateSimple func (cs *State) GetRoundStateSimpleJSON() ([]byte, error) { cs.mtx.RLock() defer cs.mtx.RUnlock() - return tmjson.Marshal(cs.RoundState.RoundStateSimple()) + return json.Marshal(cs.RoundState.RoundStateSimple()) } // GetValidators returns a copy of the current validators. diff --git a/internal/consensus/types/height_vote_set.go b/internal/consensus/types/height_vote_set.go index 86b3e2c4f..86c5d4c46 100644 --- a/internal/consensus/types/height_vote_set.go +++ b/internal/consensus/types/height_vote_set.go @@ -1,12 +1,12 @@ package types import ( + "encoding/json" "errors" "fmt" "strings" "sync" - tmjson "github.com/tendermint/tendermint/libs/json" tmmath "github.com/tendermint/tendermint/libs/math" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/types" @@ -237,7 +237,7 @@ func (hvs *HeightVoteSet) StringIndented(indent string) string { func (hvs *HeightVoteSet) MarshalJSON() ([]byte, error) { hvs.mtx.Lock() defer hvs.mtx.Unlock() - return tmjson.Marshal(hvs.toAllRoundVotes()) + return json.Marshal(hvs.toAllRoundVotes()) } func (hvs *HeightVoteSet) toAllRoundVotes() []roundVotes { diff --git a/internal/consensus/types/peer_round_state.go b/internal/consensus/types/peer_round_state.go index 9d294d9af..3f100414f 100644 --- a/internal/consensus/types/peer_round_state.go +++ b/internal/consensus/types/peer_round_state.go @@ -13,9 +13,9 @@ import ( // PeerRoundState contains the known state of a peer. // NOTE: Read-only when returned by PeerState.GetRoundState(). type PeerRoundState struct { - Height int64 `json:"height"` // Height peer is at - Round int32 `json:"round"` // Round peer is at, -1 if unknown. - Step RoundStepType `json:"step"` // Step peer is at + Height int64 `json:"height,string"` // Height peer is at + Round int32 `json:"round"` // Round peer is at, -1 if unknown. + Step RoundStepType `json:"step"` // Step peer is at // Estimated start of round 0 at this height StartTime time.Time `json:"start_time"` diff --git a/privval/file.go b/privval/file.go index 2abaced5b..a075323a8 100644 --- a/privval/file.go +++ b/privval/file.go @@ -3,6 +3,7 @@ package privval import ( "bytes" "context" + "encoding/json" "errors" "fmt" "os" @@ -72,7 +73,7 @@ func (pvKey FilePVKey) Save() error { // FilePVLastSignState stores the mutable part of PrivValidator. type FilePVLastSignState struct { - Height int64 `json:"height"` + Height int64 `json:"height,string"` Round int32 `json:"round"` Step int8 `json:"step"` Signature []byte `json:"signature,omitempty"` @@ -128,7 +129,7 @@ func (lss *FilePVLastSignState) Save() error { if outFile == "" { return errors.New("cannot save FilePVLastSignState: filePath not set") } - jsonBytes, err := tmjson.MarshalIndent(lss, "", " ") + jsonBytes, err := json.MarshalIndent(lss, "", " ") if err != nil { return err } @@ -215,7 +216,7 @@ func loadFilePV(keyFilePath, stateFilePath string, loadState bool) (*FilePV, err if err != nil { return nil, err } - err = tmjson.Unmarshal(stateJSONBytes, &pvState) + err = json.Unmarshal(stateJSONBytes, &pvState) if err != nil { return nil, fmt.Errorf("error reading PrivValidator state from %v: %w", stateFilePath, err) } diff --git a/privval/file_test.go b/privval/file_test.go index d8c6e6182..655a3d9b8 100644 --- a/privval/file_test.go +++ b/privval/file_test.go @@ -3,6 +3,7 @@ package privval import ( "context" "encoding/base64" + "encoding/json" "fmt" "os" "testing" @@ -105,7 +106,7 @@ func TestUnmarshalValidatorState(t *testing.T) { }` val := FilePVLastSignState{} - err := tmjson.Unmarshal([]byte(serialized), &val) + err := json.Unmarshal([]byte(serialized), &val) require.NoError(t, err) // make sure the values match @@ -114,7 +115,7 @@ func TestUnmarshalValidatorState(t *testing.T) { assert.EqualValues(t, val.Step, 1) // export it and make sure it is the same - out, err := tmjson.Marshal(val) + out, err := json.Marshal(val) require.NoError(t, err) assert.JSONEq(t, serialized, string(out)) } diff --git a/types/part_set.go b/types/part_set.go index 9699f2b32..9bf36279f 100644 --- a/types/part_set.go +++ b/types/part_set.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "encoding/json" "errors" "fmt" "io" @@ -10,7 +11,6 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/libs/bits" tmbytes "github.com/tendermint/tendermint/libs/bytes" - tmjson "github.com/tendermint/tendermint/libs/json" tmmath "github.com/tendermint/tendermint/libs/math" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -365,7 +365,7 @@ func (ps *PartSet) MarshalJSON() ([]byte, error) { ps.mtx.Lock() defer ps.mtx.Unlock() - return tmjson.Marshal(struct { + return json.Marshal(struct { CountTotal string `json:"count/total"` PartsBitArray *bits.BitArray `json:"parts_bit_array"` }{ diff --git a/types/vote_set.go b/types/vote_set.go index 46e6d270d..f125af317 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -2,12 +2,12 @@ package types import ( "bytes" + "encoding/json" "fmt" "strings" "sync" "github.com/tendermint/tendermint/libs/bits" - tmjson "github.com/tendermint/tendermint/libs/json" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -495,7 +495,7 @@ func (voteSet *VoteSet) StringIndented(indent string) string { func (voteSet *VoteSet) MarshalJSON() ([]byte, error) { voteSet.mtx.Lock() defer voteSet.mtx.Unlock() - return tmjson.Marshal(VoteSetJSON{ + return json.Marshal(VoteSetJSON{ voteSet.voteStrings(), voteSet.bitArrayString(), voteSet.peerMaj23s, From 6c669b70a469a9fcd99b4a44d537b52e53063592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jan 2022 11:46:41 +0100 Subject: [PATCH 03/27] build(deps): Bump technote-space/get-diff-action from 5 to 6.0.1 (#7535) Bumps [technote-space/get-diff-action](https://github.com/technote-space/get-diff-action) from 5 to 6.0.1. - [Release notes](https://github.com/technote-space/get-diff-action/releases) - [Changelog](https://github.com/technote-space/get-diff-action/blob/main/.releasegarc) - [Commits](https://github.com/technote-space/get-diff-action/compare/v5...v6.0.1) --- updated-dependencies: - dependency-name: technote-space/get-diff-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 6 +++--- .github/workflows/e2e.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/tests.yml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da51f0395..db157ad37 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go @@ -45,7 +45,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go @@ -67,7 +67,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 400741def..fced46601 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -18,7 +18,7 @@ jobs: with: go-version: '1.17' - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b808d9f77..12bf3b553 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -14,7 +14,7 @@ jobs: timeout-minutes: 8 steps: - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d8aa5e71f..4f0c7cf1d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: with: go-version: "1.17" - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go @@ -42,7 +42,7 @@ jobs: needs: tests steps: - uses: actions/checkout@v2.4.0 - - uses: technote-space/get-diff-action@v5 + - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go From f19f84bc8c40efde1efe7a45b2b058aa010fdc53 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Mon, 10 Jan 2022 13:03:53 -0500 Subject: [PATCH 04/27] test: uniquify prom IDs (#7540) --- config/config.go | 1 - config/toml.go | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 357a6c7d8..a559e4149 100644 --- a/config/config.go +++ b/config/config.go @@ -683,7 +683,6 @@ func TestP2PConfig() *P2PConfig { cfg.ListenAddress = "tcp://127.0.0.1:36656" cfg.AllowDuplicateIP = true cfg.FlushThrottleTimeout = 10 * time.Millisecond - return cfg } diff --git a/config/toml.go b/config/toml.go index 0baf4859f..530d67e18 100644 --- a/config/toml.go +++ b/config/toml.go @@ -9,6 +9,7 @@ import ( "text/template" tmos "github.com/tendermint/tendermint/libs/os" + tmrand "github.com/tendermint/tendermint/libs/rand" ) // DefaultDirPerm is the default permissions used when creating directories. @@ -549,6 +550,7 @@ func ResetTestRootWithChainID(testName string, chainID string) (*Config, error) } config := TestConfig().SetRoot(rootDir) + config.Instrumentation.Namespace = fmt.Sprintf("%s_%s_%s", testName, chainID, tmrand.Str(16)) return config, nil } From 0f3f2aa4bc54c6c6c2ed6d4f859bb0e60467cc94 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Mon, 10 Jan 2022 13:56:42 -0500 Subject: [PATCH 05/27] log: remove support for traces (#7542) --- abci/cmd/abci-cli/abci-cli.go | 4 ++-- cmd/priv_val_server/main.go | 2 +- cmd/tendermint/commands/debug/debug.go | 2 +- cmd/tendermint/commands/light.go | 2 +- cmd/tendermint/commands/root.go | 4 ++-- libs/log/default.go | 13 +++---------- libs/log/default_test.go | 4 ++-- libs/log/nop.go | 1 - libs/log/testing.go | 7 +------ light/example_test.go | 2 +- rpc/jsonrpc/jsonrpc_test.go | 2 +- rpc/jsonrpc/test/main.go | 2 +- rpc/test/helpers.go | 2 +- test/e2e/app/app.go | 2 +- test/e2e/generator/main.go | 2 +- test/e2e/node/main.go | 4 ++-- test/e2e/runner/main.go | 2 +- test/fuzz/rpc/jsonrpc/server/handler.go | 2 +- 18 files changed, 23 insertions(+), 36 deletions(-) diff --git a/abci/cmd/abci-cli/abci-cli.go b/abci/cmd/abci-cli/abci-cli.go index 783c41dbb..512f4e772 100644 --- a/abci/cmd/abci-cli/abci-cli.go +++ b/abci/cmd/abci-cli/abci-cli.go @@ -60,7 +60,7 @@ var RootCmd = &cobra.Command{ } if logger == nil { - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) } if client == nil { @@ -575,7 +575,7 @@ func cmdQuery(cmd *cobra.Command, args []string) error { } func cmdKVStore(cmd *cobra.Command, args []string) error { - logger := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) // Create the application - in memory or persisted to disk var app types.Application diff --git a/cmd/priv_val_server/main.go b/cmd/priv_val_server/main.go index 0708edd5c..baacadf1e 100644 --- a/cmd/priv_val_server/main.go +++ b/cmd/priv_val_server/main.go @@ -46,7 +46,7 @@ func main() { rootCA = flag.String("rootcafile", "", "absolute path to root CA") prometheusAddr = flag.String("prometheus-addr", "", "address for prometheus endpoint (host:port)") - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false). + logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo). With("module", "priv_val") ) flag.Parse() diff --git a/cmd/tendermint/commands/debug/debug.go b/cmd/tendermint/commands/debug/debug.go index e07f7978d..2bf76babc 100644 --- a/cmd/tendermint/commands/debug/debug.go +++ b/cmd/tendermint/commands/debug/debug.go @@ -15,7 +15,7 @@ var ( flagProfAddr = "pprof-laddr" flagFrequency = "frequency" - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) ) // DebugCmd defines the root command containing subcommands that assist in diff --git a/cmd/tendermint/commands/light.go b/cmd/tendermint/commands/light.go index 31171174d..9cad3397f 100644 --- a/cmd/tendermint/commands/light.go +++ b/cmd/tendermint/commands/light.go @@ -102,7 +102,7 @@ func init() { } func runProxy(cmd *cobra.Command, args []string) error { - logger, err := log.NewDefaultLogger(logFormat, logLevel, false) + logger, err := log.NewDefaultLogger(logFormat, logLevel) if err != nil { return err } diff --git a/cmd/tendermint/commands/root.go b/cmd/tendermint/commands/root.go index 9e1333885..354b414bf 100644 --- a/cmd/tendermint/commands/root.go +++ b/cmd/tendermint/commands/root.go @@ -13,7 +13,7 @@ import ( var ( config = cfg.DefaultConfig() - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) ctxTimeout = 4 * time.Second ) @@ -55,7 +55,7 @@ var RootCmd = &cobra.Command{ return err } - logger, err = log.NewDefaultLogger(config.LogFormat, config.LogLevel, false) + logger, err = log.NewDefaultLogger(config.LogFormat, config.LogLevel) if err != nil { return err } diff --git a/libs/log/default.go b/libs/log/default.go index ca48fcd72..47800a3d9 100644 --- a/libs/log/default.go +++ b/libs/log/default.go @@ -14,8 +14,6 @@ var _ Logger = (*defaultLogger)(nil) type defaultLogger struct { zerolog.Logger - - trace bool } // NewDefaultLogger returns a default logger that can be used within Tendermint @@ -26,7 +24,7 @@ type defaultLogger struct { // Since zerolog supports typed structured logging and it is difficult to reflect // that in a generic interface, all logging methods accept a series of key/value // pair tuples, where the key must be a string. -func NewDefaultLogger(format, level string, trace bool) (Logger, error) { +func NewDefaultLogger(format, level string) (Logger, error) { var logWriter io.Writer switch strings.ToLower(format) { case LogFormatPlain, LogFormatText: @@ -59,14 +57,13 @@ func NewDefaultLogger(format, level string, trace bool) (Logger, error) { return defaultLogger{ Logger: zerolog.New(logWriter).Level(logLevel).With().Timestamp().Logger(), - trace: trace, }, nil } // MustNewDefaultLogger delegates a call NewDefaultLogger where it panics on // error. -func MustNewDefaultLogger(format, level string, trace bool) Logger { - logger, err := NewDefaultLogger(format, level, trace) +func MustNewDefaultLogger(format, level string) Logger { + logger, err := NewDefaultLogger(format, level) if err != nil { panic(err) } @@ -80,9 +77,6 @@ func (l defaultLogger) Info(msg string, keyVals ...interface{}) { func (l defaultLogger) Error(msg string, keyVals ...interface{}) { e := l.Logger.Error() - if l.trace { - e = e.Stack() - } e.Fields(getLogFields(keyVals...)).Msg(msg) } @@ -94,7 +88,6 @@ func (l defaultLogger) Debug(msg string, keyVals ...interface{}) { func (l defaultLogger) With(keyVals ...interface{}) Logger { return defaultLogger{ Logger: l.Logger.With().Fields(getLogFields(keyVals...)).Logger(), - trace: l.trace, } } diff --git a/libs/log/default_test.go b/libs/log/default_test.go index c66508f04..ca854c7ad 100644 --- a/libs/log/default_test.go +++ b/libs/log/default_test.go @@ -34,11 +34,11 @@ func TestNewDefaultLogger(t *testing.T) { tc := tc t.Run(name, func(t *testing.T) { - _, err := log.NewDefaultLogger(tc.format, tc.level, false) + _, err := log.NewDefaultLogger(tc.format, tc.level) if tc.expectErr { require.Error(t, err) require.Panics(t, func() { - _ = log.MustNewDefaultLogger(tc.format, tc.level, false) + _ = log.MustNewDefaultLogger(tc.format, tc.level) }) } else { require.NoError(t, err) diff --git a/libs/log/nop.go b/libs/log/nop.go index 4b3bfb196..e49540c10 100644 --- a/libs/log/nop.go +++ b/libs/log/nop.go @@ -7,6 +7,5 @@ import ( func NewNopLogger() Logger { return defaultLogger{ Logger: zerolog.Nop(), - trace: false, } } diff --git a/libs/log/testing.go b/libs/log/testing.go index b76bb77c6..92b84c742 100644 --- a/libs/log/testing.go +++ b/libs/log/testing.go @@ -32,7 +32,7 @@ func TestingLogger() Logger { } if testing.Verbose() { - testingLogger = MustNewDefaultLogger(LogFormatText, LogLevelDebug, true) + testingLogger = MustNewDefaultLogger(LogFormatText, LogLevelDebug) } else { testingLogger = NewNopLogger() } @@ -73,13 +73,8 @@ func NewTestingLoggerWithLevel(t testing.TB, level string) Logger { if err != nil { t.Fatalf("failed to parse log level (%s): %v", level, err) } - trace := false - if testing.Verbose() { - trace = true - } return defaultLogger{ Logger: zerolog.New(newSyncWriter(testingWriter{t})).Level(logLevel), - trace: trace, } } diff --git a/light/example_test.go b/light/example_test.go index c2dfc7fb0..d22525b30 100644 --- a/light/example_test.go +++ b/light/example_test.go @@ -26,7 +26,7 @@ func ExampleClient() { stdlog.Fatal(err) } - logger, err := log.NewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger, err := log.NewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) if err != nil { stdlog.Fatal(err) } diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index 916f85ca1..e43e14d42 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -94,7 +94,7 @@ func TestMain(m *testing.M) { // launch unix and tcp servers func setup(ctx context.Context) error { - logger := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) cmd := exec.Command("rm", "-f", unixSocket) err := cmd.Start() diff --git a/rpc/jsonrpc/test/main.go b/rpc/jsonrpc/test/main.go index f11709f98..4517f0298 100644 --- a/rpc/jsonrpc/test/main.go +++ b/rpc/jsonrpc/test/main.go @@ -28,7 +28,7 @@ type Result struct { func main() { var ( mux = http.NewServeMux() - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) ) ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) diff --git a/rpc/test/helpers.go b/rpc/test/helpers.go index 90c3b2e49..b7db50f6c 100644 --- a/rpc/test/helpers.go +++ b/rpc/test/helpers.go @@ -89,7 +89,7 @@ func StartTendermint( if nodeOpts.suppressStdout { logger = log.NewNopLogger() } else { - logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) } papp := abciclient.NewLocalCreator(app) tmNode, err := node.New(ctx, conf, logger, papp, nil) diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 5a782fa33..f2bff3713 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -89,7 +89,7 @@ func NewApplication(cfg *Config) (*Application, error) { return nil, err } return &Application{ - logger: log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false), + logger: log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo), state: state, snapshots: snapshots, cfg: cfg, diff --git a/test/e2e/generator/main.go b/test/e2e/generator/main.go index 38f36d0da..10b809279 100644 --- a/test/e2e/generator/main.go +++ b/test/e2e/generator/main.go @@ -17,7 +17,7 @@ const ( randomSeed int64 = 4827085738 ) -var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) +var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) func main() { NewCLI().Run() diff --git a/test/e2e/node/main.go b/test/e2e/node/main.go index 2509c9767..5a60a20bd 100644 --- a/test/e2e/node/main.go +++ b/test/e2e/node/main.go @@ -34,7 +34,7 @@ import ( e2e "github.com/tendermint/tendermint/test/e2e/pkg" ) -var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) +var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) // main is the binary entrypoint. func main() { @@ -297,7 +297,7 @@ func setupNode() (*config.Config, log.Logger, error) { return nil, nil, fmt.Errorf("error in config file: %w", err) } - nodeLogger, err := log.NewDefaultLogger(tmcfg.LogFormat, tmcfg.LogLevel, false) + nodeLogger, err := log.NewDefaultLogger(tmcfg.LogFormat, tmcfg.LogLevel) if err != nil { return nil, nil, err } diff --git a/test/e2e/runner/main.go b/test/e2e/runner/main.go index c163c5e96..83d1327be 100644 --- a/test/e2e/runner/main.go +++ b/test/e2e/runner/main.go @@ -16,7 +16,7 @@ import ( const randomSeed = 2308084734268 -var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) +var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) func main() { NewCLI().Run() diff --git a/test/fuzz/rpc/jsonrpc/server/handler.go b/test/fuzz/rpc/jsonrpc/server/handler.go index 723c0e030..61779b7f4 100644 --- a/test/fuzz/rpc/jsonrpc/server/handler.go +++ b/test/fuzz/rpc/jsonrpc/server/handler.go @@ -19,7 +19,7 @@ var mux *http.ServeMux func init() { mux = http.NewServeMux() - lgr := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false) + lgr := log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo) rs.RegisterRPCFuncs(mux, rpcFuncMap, lgr) } From 211d755aca93b27659614496b0e0f5aa8111a61e Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Mon, 10 Jan 2022 11:20:30 -0800 Subject: [PATCH 06/27] rpc: remove positional parameter encoding from clients (#7545) Apart from the tests for the websocket client, positional parameters are not used by RPC clients. The server supports both arrays and objects, but the client only needs to provide one or the other. --- rpc/jsonrpc/client/ws_client.go | 10 ---------- rpc/jsonrpc/jsonrpc_test.go | 31 ------------------------------- rpc/jsonrpc/types/types.go | 18 ------------------ 3 files changed, 59 deletions(-) diff --git a/rpc/jsonrpc/client/ws_client.go b/rpc/jsonrpc/client/ws_client.go index 98cff05ce..624b08776 100644 --- a/rpc/jsonrpc/client/ws_client.go +++ b/rpc/jsonrpc/client/ws_client.go @@ -224,16 +224,6 @@ func (c *WSClient) Call(ctx context.Context, method string, params map[string]in return c.Send(ctx, request) } -// CallWithArrayParams enqueues a call request onto the Send queue. Params are -// in a form of array (e.g. []interface{}{"abcd"}). Requests are JSON encoded. -func (c *WSClient) CallWithArrayParams(ctx context.Context, method string, params []interface{}) error { - request, err := rpctypes.ArrayToRequest(c.nextRequestID(), method, params) - if err != nil { - return err - } - return c.Send(ctx, request) -} - // Private methods func (c *WSClient) nextRequestID() rpctypes.JSONRPCIntID { diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index e43e14d42..3e1fbded1 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -329,37 +329,6 @@ func TestWSNewWSRPCFunc(t *testing.T) { assert.Equal(t, got, val) } -func TestWSHandlesArrayParams(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - cl, err := client.NewWS(tcpAddr, websocketEndpoint) - require.NoError(t, err) - - cl.Logger = log.NewTestingLogger(t) - require.Nil(t, cl.Start(ctx)) - t.Cleanup(func() { - if err := cl.Stop(); err != nil { - t.Error(err) - } - }) - - val := testVal - params := []interface{}{val} - err = cl.CallWithArrayParams(ctx, "echo_ws", params) - require.NoError(t, err) - - msg := <-cl.ResponsesCh - if msg.Error != nil { - t.Fatalf("%+v", err) - } - result := new(ResultEcho) - err = json.Unmarshal(msg.Result, result) - require.NoError(t, err) - got := result.Value - assert.Equal(t, got, val) -} - // TestWSClientPingPong checks that a client & server exchange pings // & pongs so connection stays alive. func TestWSClientPingPong(t *testing.T) { diff --git a/rpc/jsonrpc/types/types.go b/rpc/jsonrpc/types/types.go index 74a4cc52b..617be7ebd 100644 --- a/rpc/jsonrpc/types/types.go +++ b/rpc/jsonrpc/types/types.go @@ -116,24 +116,6 @@ func MapToRequest(id jsonrpcid, method string, params map[string]interface{}) (R return NewRPCRequest(id, method, payload), nil } -func ArrayToRequest(id jsonrpcid, method string, params []interface{}) (RPCRequest, error) { - var paramsMap = make([]json.RawMessage, len(params)) - for i, value := range params { - valueJSON, err := tmjson.Marshal(value) - if err != nil { - return RPCRequest{}, err - } - paramsMap[i] = valueJSON - } - - payload, err := json.Marshal(paramsMap) - if err != nil { - return RPCRequest{}, err - } - - return NewRPCRequest(id, method, payload), nil -} - //---------------------------------------- // RESPONSE From 8e58c564c01556556d57de425ad4ba36792c479a Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Mon, 10 Jan 2022 11:52:52 -0800 Subject: [PATCH 07/27] rpc: collapse Caller and HTTPClient interfaces. (#7548) These two interfaces are identical, and besides HTTPClient being confusingly named, all but one location uses Caller. Update that one location, and drop the redundant interface. --- rpc/jsonrpc/client/http_json_client.go | 8 -------- rpc/jsonrpc/jsonrpc_test.go | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rpc/jsonrpc/client/http_json_client.go b/rpc/jsonrpc/client/http_json_client.go index 45f516f04..029ec3b34 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -106,12 +106,6 @@ func (u parsedURL) GetTrimmedURL() string { //------------------------------------------------------------- -// HTTPClient is a common interface for JSON-RPC HTTP clients. -type HTTPClient interface { - // Call calls the given method with the params and returns a result. - Call(ctx context.Context, method string, params map[string]interface{}, result interface{}) (interface{}, error) -} - // Caller implementers can facilitate calling the JSON-RPC endpoint. type Caller interface { Call(ctx context.Context, method string, params map[string]interface{}, result interface{}) (interface{}, error) @@ -134,8 +128,6 @@ type Client struct { nextReqID int } -var _ HTTPClient = (*Client)(nil) - // Both Client and RequestBatch can facilitate calls to the JSON // RPC endpoint. var _ Caller = (*Client)(nil) diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index 3e1fbded1..b22dfa3d7 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -187,7 +187,7 @@ func echoDataBytesViaHTTP(ctx context.Context, cl client.Caller, bytes tmbytes.H return result.Value, nil } -func testWithHTTPClient(ctx context.Context, t *testing.T, cl client.HTTPClient) { +func testWithHTTPClient(ctx context.Context, t *testing.T, cl client.Caller) { val := testVal got, err := echoViaHTTP(ctx, cl, val) require.NoError(t, err) From d331a086078c7839d7bd0057721df236fde042fe Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Mon, 10 Jan 2022 15:38:20 -0500 Subject: [PATCH 08/27] statesync: use specific testing.T logger for tests (#7543) --- internal/statesync/reactor_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index 8e1256c10..4ff02d0bc 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -161,13 +161,15 @@ func setup( } } + logger := log.NewTestingLogger(t) + var err error rts.reactor, err = NewReactor( ctx, factory.DefaultTestChainID, 1, *cfg, - log.TestingLogger(), + logger.With("component", "reactor"), conn, connQuery, chCreator, @@ -181,7 +183,7 @@ func setup( rts.syncer = newSyncer( *cfg, - log.NewNopLogger(), + logger.With("component", "syncer"), conn, connQuery, stateProvider, From 692701a551d1e8f4e9a23e6362e7728ca22d72e2 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Mon, 10 Jan 2022 16:26:40 -0500 Subject: [PATCH 09/27] abci: socket server shutdown response handler (#7547) --- abci/server/socket_server.go | 26 +++++++++++++++++++------- abci/tests/client_server_test.go | 5 +++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/abci/server/socket_server.go b/abci/server/socket_server.go index f98b9d153..9496faf47 100644 --- a/abci/server/socket_server.go +++ b/abci/server/socket_server.go @@ -259,14 +259,26 @@ func (s *SocketServer) handleResponses( responses <-chan *types.Response, ) { bw := bufio.NewWriter(conn) - for res := range responses { - if err := types.WriteMessage(res, bw); err != nil { - closeConn <- fmt.Errorf("error writing message: %w", err) - return - } - if err := bw.Flush(); err != nil { - closeConn <- fmt.Errorf("error flushing write buffer: %w", err) + for { + select { + case <-ctx.Done(): return + case res := <-responses: + if err := types.WriteMessage(res, bw); err != nil { + select { + case <-ctx.Done(): + case closeConn <- fmt.Errorf("error writing message: %w", err): + } + return + } + if err := bw.Flush(); err != nil { + select { + case <-ctx.Done(): + case closeConn <- fmt.Errorf("error flushing write buffer: %w", err): + } + + return + } } } } diff --git a/abci/tests/client_server_test.go b/abci/tests/client_server_test.go index 2581714e8..a97c0c7c4 100644 --- a/abci/tests/client_server_test.go +++ b/abci/tests/client_server_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/fortytw2/leaktest" "github.com/stretchr/testify/assert" abciclientent "github.com/tendermint/tendermint/abci/client" @@ -13,6 +14,8 @@ import ( ) func TestClientServerNoAddrPrefix(t *testing.T) { + t.Cleanup(leaktest.Check(t)) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -27,9 +30,11 @@ func TestClientServerNoAddrPrefix(t *testing.T) { assert.NoError(t, err, "expected no error on NewServer") err = server.Start(ctx) assert.NoError(t, err, "expected no error on server.Start") + t.Cleanup(server.Wait) client, err := abciclientent.NewClient(logger, addr, transport, true) assert.NoError(t, err, "expected no error on NewClient") err = client.Start(ctx) assert.NoError(t, err, "expected no error on client.Start") + t.Cleanup(client.Wait) } From 6291d22f46f4c4f9121375af700dbdafa51577e7 Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Mon, 10 Jan 2022 13:56:43 -0800 Subject: [PATCH 10/27] rpc: simplify the JSON-RPC client Caller interface (#7549) * Update Caller interface and its documentation. * Rework MapToRequest as ParamsToRequest. The old interface returned the result as well as populating it. Nothing was using this, so drop the duplicated value from the return signature. Clarify the documentation on the Caller type. Rework the MapToRequest helper to take an arbitrary value instead of only a map. This is groundwork for getting rid of the custom marshaling code. For now, however, the implementation preserves the existing behaviour for the map, until we can replace those. --- rpc/client/http/http.go | 91 +++++++++----------------- rpc/jsonrpc/client/decode.go | 18 ++--- rpc/jsonrpc/client/http_json_client.go | 42 ++++++------ rpc/jsonrpc/client/ws_client.go | 2 +- rpc/jsonrpc/jsonrpc_test.go | 8 +-- rpc/jsonrpc/server/ws_handler_test.go | 2 +- rpc/jsonrpc/types/types.go | 28 +++++--- rpc/test/helpers.go | 2 +- 8 files changed, 81 insertions(+), 112 deletions(-) diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index d18671fd0..de4269179 100644 --- a/rpc/client/http/http.go +++ b/rpc/client/http/http.go @@ -203,21 +203,17 @@ func (b *BatchHTTP) Count() int { func (c *baseRPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { result := new(coretypes.ResultStatus) - _, err := c.caller.Call(ctx, "status", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "status", map[string]interface{}{}, result); err != nil { return nil, err } - return result, nil } func (c *baseRPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { result := new(coretypes.ResultABCIInfo) - _, err := c.caller.Call(ctx, "abci_info", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "abci_info", map[string]interface{}{}, result); err != nil { return nil, err } - return result, nil } @@ -235,13 +231,11 @@ func (c *baseRPCClient) ABCIQueryWithOptions( data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { result := new(coretypes.ResultABCIQuery) - _, err := c.caller.Call(ctx, "abci_query", + if err := c.caller.Call(ctx, "abci_query", map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove}, - result) - if err != nil { + result); err != nil { return nil, err } - return result, nil } @@ -250,8 +244,7 @@ func (c *baseRPCClient) BroadcastTxCommit( tx types.Tx, ) (*coretypes.ResultBroadcastTxCommit, error) { result := new(coretypes.ResultBroadcastTxCommit) - _, err := c.caller.Call(ctx, "broadcast_tx_commit", map[string]interface{}{"tx": tx}, result) - if err != nil { + if err := c.caller.Call(ctx, "broadcast_tx_commit", map[string]interface{}{"tx": tx}, result); err != nil { return nil, err } return result, nil @@ -277,8 +270,7 @@ func (c *baseRPCClient) broadcastTX( tx types.Tx, ) (*coretypes.ResultBroadcastTx, error) { result := new(coretypes.ResultBroadcastTx) - _, err := c.caller.Call(ctx, route, map[string]interface{}{"tx": tx}, result) - if err != nil { + if err := c.caller.Call(ctx, route, map[string]interface{}{"tx": tx}, result); err != nil { return nil, err } return result, nil @@ -293,8 +285,7 @@ func (c *baseRPCClient) UnconfirmedTxs( if limit != nil { params["limit"] = limit } - _, err := c.caller.Call(ctx, "unconfirmed_txs", params, result) - if err != nil { + if err := c.caller.Call(ctx, "unconfirmed_txs", params, result); err != nil { return nil, err } return result, nil @@ -302,8 +293,7 @@ func (c *baseRPCClient) UnconfirmedTxs( func (c *baseRPCClient) NumUnconfirmedTxs(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) { result := new(coretypes.ResultUnconfirmedTxs) - _, err := c.caller.Call(ctx, "num_unconfirmed_txs", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "num_unconfirmed_txs", map[string]interface{}{}, result); err != nil { return nil, err } return result, nil @@ -311,16 +301,14 @@ func (c *baseRPCClient) NumUnconfirmedTxs(ctx context.Context) (*coretypes.Resul func (c *baseRPCClient) CheckTx(ctx context.Context, tx types.Tx) (*coretypes.ResultCheckTx, error) { result := new(coretypes.ResultCheckTx) - _, err := c.caller.Call(ctx, "check_tx", map[string]interface{}{"tx": tx}, result) - if err != nil { + if err := c.caller.Call(ctx, "check_tx", map[string]interface{}{"tx": tx}, result); err != nil { return nil, err } return result, nil } func (c *baseRPCClient) RemoveTx(ctx context.Context, txKey types.TxKey) error { - _, err := c.caller.Call(ctx, "remove_tx", map[string]interface{}{"tx_key": txKey}, nil) - if err != nil { + if err := c.caller.Call(ctx, "remove_tx", map[string]interface{}{"tx_key": txKey}, nil); err != nil { return err } return nil @@ -328,8 +316,7 @@ func (c *baseRPCClient) RemoveTx(ctx context.Context, txKey types.TxKey) error { func (c *baseRPCClient) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, error) { result := new(coretypes.ResultNetInfo) - _, err := c.caller.Call(ctx, "net_info", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "net_info", map[string]interface{}{}, result); err != nil { return nil, err } return result, nil @@ -337,8 +324,7 @@ func (c *baseRPCClient) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, func (c *baseRPCClient) DumpConsensusState(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) { result := new(coretypes.ResultDumpConsensusState) - _, err := c.caller.Call(ctx, "dump_consensus_state", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "dump_consensus_state", map[string]interface{}{}, result); err != nil { return nil, err } return result, nil @@ -346,8 +332,7 @@ func (c *baseRPCClient) DumpConsensusState(ctx context.Context) (*coretypes.Resu func (c *baseRPCClient) ConsensusState(ctx context.Context) (*coretypes.ResultConsensusState, error) { result := new(coretypes.ResultConsensusState) - _, err := c.caller.Call(ctx, "consensus_state", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "consensus_state", map[string]interface{}{}, result); err != nil { return nil, err } return result, nil @@ -362,8 +347,7 @@ func (c *baseRPCClient) ConsensusParams( if height != nil { params["height"] = height } - _, err := c.caller.Call(ctx, "consensus_params", params, result) - if err != nil { + if err := c.caller.Call(ctx, "consensus_params", params, result); err != nil { return nil, err } return result, nil @@ -371,8 +355,7 @@ func (c *baseRPCClient) ConsensusParams( func (c *baseRPCClient) Health(ctx context.Context) (*coretypes.ResultHealth, error) { result := new(coretypes.ResultHealth) - _, err := c.caller.Call(ctx, "health", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "health", map[string]interface{}{}, result); err != nil { return nil, err } return result, nil @@ -384,10 +367,9 @@ func (c *baseRPCClient) BlockchainInfo( maxHeight int64, ) (*coretypes.ResultBlockchainInfo, error) { result := new(coretypes.ResultBlockchainInfo) - _, err := c.caller.Call(ctx, "blockchain", + if err := c.caller.Call(ctx, "blockchain", map[string]interface{}{"minHeight": minHeight, "maxHeight": maxHeight}, - result) - if err != nil { + result); err != nil { return nil, err } return result, nil @@ -395,8 +377,7 @@ func (c *baseRPCClient) BlockchainInfo( func (c *baseRPCClient) Genesis(ctx context.Context) (*coretypes.ResultGenesis, error) { result := new(coretypes.ResultGenesis) - _, err := c.caller.Call(ctx, "genesis", map[string]interface{}{}, result) - if err != nil { + if err := c.caller.Call(ctx, "genesis", map[string]interface{}{}, result); err != nil { return nil, err } return result, nil @@ -404,8 +385,7 @@ func (c *baseRPCClient) Genesis(ctx context.Context) (*coretypes.ResultGenesis, func (c *baseRPCClient) GenesisChunked(ctx context.Context, id uint) (*coretypes.ResultGenesisChunk, error) { result := new(coretypes.ResultGenesisChunk) - _, err := c.caller.Call(ctx, "genesis_chunked", map[string]interface{}{"chunk": id}, result) - if err != nil { + if err := c.caller.Call(ctx, "genesis_chunked", map[string]interface{}{"chunk": id}, result); err != nil { return nil, err } return result, nil @@ -417,8 +397,7 @@ func (c *baseRPCClient) Block(ctx context.Context, height *int64) (*coretypes.Re if height != nil { params["height"] = height } - _, err := c.caller.Call(ctx, "block", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block", params, result); err != nil { return nil, err } return result, nil @@ -429,8 +408,7 @@ func (c *baseRPCClient) BlockByHash(ctx context.Context, hash bytes.HexBytes) (* params := map[string]interface{}{ "hash": hash, } - _, err := c.caller.Call(ctx, "block_by_hash", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block_by_hash", params, result); err != nil { return nil, err } return result, nil @@ -445,8 +423,7 @@ func (c *baseRPCClient) BlockResults( if height != nil { params["height"] = height } - _, err := c.caller.Call(ctx, "block_results", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block_results", params, result); err != nil { return nil, err } return result, nil @@ -458,8 +435,7 @@ func (c *baseRPCClient) Header(ctx context.Context, height *int64) (*coretypes.R if height != nil { params["height"] = height } - _, err := c.caller.Call(ctx, "header", params, result) - if err != nil { + if err := c.caller.Call(ctx, "header", params, result); err != nil { return nil, err } return result, nil @@ -470,8 +446,7 @@ func (c *baseRPCClient) HeaderByHash(ctx context.Context, hash bytes.HexBytes) ( params := map[string]interface{}{ "hash": hash, } - _, err := c.caller.Call(ctx, "header_by_hash", params, result) - if err != nil { + if err := c.caller.Call(ctx, "header_by_hash", params, result); err != nil { return nil, err } return result, nil @@ -483,8 +458,7 @@ func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*coretypes.R if height != nil { params["height"] = height } - _, err := c.caller.Call(ctx, "commit", params, result) - if err != nil { + if err := c.caller.Call(ctx, "commit", params, result); err != nil { return nil, err } return result, nil @@ -496,8 +470,7 @@ func (c *baseRPCClient) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) "hash": hash, "prove": prove, } - _, err := c.caller.Call(ctx, "tx", params, result) - if err != nil { + if err := c.caller.Call(ctx, "tx", params, result); err != nil { return nil, err } return result, nil @@ -526,8 +499,7 @@ func (c *baseRPCClient) TxSearch( params["per_page"] = perPage } - _, err := c.caller.Call(ctx, "tx_search", params, result) - if err != nil { + if err := c.caller.Call(ctx, "tx_search", params, result); err != nil { return nil, err } @@ -554,8 +526,7 @@ func (c *baseRPCClient) BlockSearch( params["per_page"] = perPage } - _, err := c.caller.Call(ctx, "block_search", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block_search", params, result); err != nil { return nil, err } @@ -579,8 +550,7 @@ func (c *baseRPCClient) Validators( if height != nil { params["height"] = height } - _, err := c.caller.Call(ctx, "validators", params, result) - if err != nil { + if err := c.caller.Call(ctx, "validators", params, result); err != nil { return nil, err } return result, nil @@ -591,8 +561,7 @@ func (c *baseRPCClient) BroadcastEvidence( ev types.Evidence, ) (*coretypes.ResultBroadcastEvidence, error) { result := new(coretypes.ResultBroadcastEvidence) - _, err := c.caller.Call(ctx, "broadcast_evidence", map[string]interface{}{"evidence": ev}, result) - if err != nil { + if err := c.caller.Call(ctx, "broadcast_evidence", map[string]interface{}{"evidence": ev}, result); err != nil { return nil, err } return result, nil diff --git a/rpc/jsonrpc/client/decode.go b/rpc/jsonrpc/client/decode.go index f69926cb7..5d41a94c0 100644 --- a/rpc/jsonrpc/client/decode.go +++ b/rpc/jsonrpc/client/decode.go @@ -9,33 +9,27 @@ import ( rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) -func unmarshalResponseBytes( - responseBytes []byte, - expectedID rpctypes.JSONRPCIntID, - result interface{}, -) (interface{}, error) { - +func unmarshalResponseBytes(responseBytes []byte, expectedID rpctypes.JSONRPCIntID, result interface{}) error { // Read response. If rpc/core/types is imported, the result will unmarshal // into the correct type. response := &rpctypes.RPCResponse{} if err := json.Unmarshal(responseBytes, response); err != nil { - return nil, fmt.Errorf("error unmarshaling: %w", err) + return fmt.Errorf("error unmarshaling: %w", err) } if response.Error != nil { - return nil, response.Error + return response.Error } if err := validateAndVerifyID(response, expectedID); err != nil { - return nil, fmt.Errorf("wrong ID: %w", err) + return fmt.Errorf("wrong ID: %w", err) } // Unmarshal the RawMessage into the result. if err := tmjson.Unmarshal(response.Result, result); err != nil { - return nil, fmt.Errorf("error unmarshaling result: %w", err) + return fmt.Errorf("error unmarshaling result: %w", err) } - - return result, nil + return nil } func unmarshalResponseBytesArray( diff --git a/rpc/jsonrpc/client/http_json_client.go b/rpc/jsonrpc/client/http_json_client.go index 029ec3b34..b2823d5e7 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -106,9 +106,15 @@ func (u parsedURL) GetTrimmedURL() string { //------------------------------------------------------------- -// Caller implementers can facilitate calling the JSON-RPC endpoint. +// A Caller handles the round trip of a single JSON-RPC request. The +// implementation is responsible for assigning request IDs, marshaling +// parameters, and unmarshaling results. type Caller interface { - Call(ctx context.Context, method string, params map[string]interface{}, result interface{}) (interface{}, error) + // Call sends a new request for method to the server with the given + // parameters. If params == nil, the request has empty parameters. + // If result == nil, any result value must be discarded without error. + // Otherwise the concrete value of result must be a pointer. + Call(ctx context.Context, method string, params, result interface{}) error } //------------------------------------------------------------- @@ -174,28 +180,23 @@ func NewWithHTTPClient(remote string, c *http.Client) (*Client, error) { // Call issues a POST HTTP request. Requests are JSON encoded. Content-Type: // application/json. -func (c *Client) Call( - ctx context.Context, - method string, - params map[string]interface{}, - result interface{}, -) (interface{}, error) { +func (c *Client) Call(ctx context.Context, method string, params, result interface{}) error { id := c.nextRequestID() - request, err := rpctypes.MapToRequest(id, method, params) + request, err := rpctypes.ParamsToRequest(id, method, params) if err != nil { - return nil, fmt.Errorf("failed to encode params: %w", err) + return fmt.Errorf("failed to encode params: %w", err) } requestBytes, err := json.Marshal(request) if err != nil { - return nil, fmt.Errorf("failed to marshal request: %w", err) + return fmt.Errorf("failed to marshal request: %w", err) } requestBuf := bytes.NewBuffer(requestBytes) httpRequest, err := http.NewRequestWithContext(ctx, http.MethodPost, c.address, requestBuf) if err != nil { - return nil, fmt.Errorf("request setup failed: %w", err) + return fmt.Errorf("request setup failed: %w", err) } httpRequest.Header.Set("Content-Type", "application/json") @@ -206,14 +207,14 @@ func (c *Client) Call( httpResponse, err := c.client.Do(httpRequest) if err != nil { - return nil, err + return err } defer httpResponse.Body.Close() responseBytes, err := io.ReadAll(httpResponse.Body) if err != nil { - return nil, fmt.Errorf("failed to read response body: %w", err) + return fmt.Errorf("failed to read response body: %w", err) } return unmarshalResponseBytes(responseBytes, id, result) @@ -340,19 +341,14 @@ func (b *RequestBatch) Send(ctx context.Context) ([]interface{}, error) { // Call enqueues a request to call the given RPC method with the specified // parameters, in the same way that the `Client.Call` function would. -func (b *RequestBatch) Call( - _ context.Context, - method string, - params map[string]interface{}, - result interface{}, -) (interface{}, error) { +func (b *RequestBatch) Call(_ context.Context, method string, params, result interface{}) error { id := b.client.nextRequestID() - request, err := rpctypes.MapToRequest(id, method, params) + request, err := rpctypes.ParamsToRequest(id, method, params) if err != nil { - return nil, err + return err } b.enqueue(&jsonRPCBufferedRequest{request: request, result: result}) - return result, nil + return nil } //------------------------------------------------------------- diff --git a/rpc/jsonrpc/client/ws_client.go b/rpc/jsonrpc/client/ws_client.go index 624b08776..80520e2a3 100644 --- a/rpc/jsonrpc/client/ws_client.go +++ b/rpc/jsonrpc/client/ws_client.go @@ -217,7 +217,7 @@ func (c *WSClient) Send(ctx context.Context, request rpctypes.RPCRequest) error // Call enqueues a call request onto the Send queue. Requests are JSON encoded. func (c *WSClient) Call(ctx context.Context, method string, params map[string]interface{}) error { - request, err := rpctypes.MapToRequest(c.nextRequestID(), method, params) + request, err := rpctypes.ParamsToRequest(c.nextRequestID(), method, params) if err != nil { return err } diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index b22dfa3d7..2c353e508 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -148,7 +148,7 @@ func echoViaHTTP(ctx context.Context, cl client.Caller, val string) (string, err "arg": val, } result := new(ResultEcho) - if _, err := cl.Call(ctx, "echo", params, result); err != nil { + if err := cl.Call(ctx, "echo", params, result); err != nil { return "", err } return result.Value, nil @@ -159,7 +159,7 @@ func echoIntViaHTTP(ctx context.Context, cl client.Caller, val int) (int, error) "arg": val, } result := new(ResultEchoInt) - if _, err := cl.Call(ctx, "echo_int", params, result); err != nil { + if err := cl.Call(ctx, "echo_int", params, result); err != nil { return 0, err } return result.Value, nil @@ -170,7 +170,7 @@ func echoBytesViaHTTP(ctx context.Context, cl client.Caller, bytes []byte) ([]by "arg": bytes, } result := new(ResultEchoBytes) - if _, err := cl.Call(ctx, "echo_bytes", params, result); err != nil { + if err := cl.Call(ctx, "echo_bytes", params, result); err != nil { return []byte{}, err } return result.Value, nil @@ -181,7 +181,7 @@ func echoDataBytesViaHTTP(ctx context.Context, cl client.Caller, bytes tmbytes.H "arg": bytes, } result := new(ResultEchoDataBytes) - if _, err := cl.Call(ctx, "echo_data_bytes", params, result); err != nil { + if err := cl.Call(ctx, "echo_data_bytes", params, result); err != nil { return []byte{}, err } return result.Value, nil diff --git a/rpc/jsonrpc/server/ws_handler_test.go b/rpc/jsonrpc/server/ws_handler_test.go index 11c97ade0..00d6a18a5 100644 --- a/rpc/jsonrpc/server/ws_handler_test.go +++ b/rpc/jsonrpc/server/ws_handler_test.go @@ -28,7 +28,7 @@ func TestWebsocketManagerHandler(t *testing.T) { } // check basic functionality works - req, err := rpctypes.MapToRequest( + req, err := rpctypes.ParamsToRequest( rpctypes.JSONRPCStringID("TestWebsocketManager"), "c", map[string]interface{}{"s": "a", "i": 10}, diff --git a/rpc/jsonrpc/types/types.go b/rpc/jsonrpc/types/types.go index 617be7ebd..a44faf92f 100644 --- a/rpc/jsonrpc/types/types.go +++ b/rpc/jsonrpc/types/types.go @@ -98,17 +98,27 @@ func (req RPCRequest) String() string { return fmt.Sprintf("RPCRequest{%s %s/%X}", req.ID, req.Method, req.Params) } -func MapToRequest(id jsonrpcid, method string, params map[string]interface{}) (RPCRequest, error) { - var paramsMap = make(map[string]json.RawMessage, len(params)) - for name, value := range params { - valueJSON, err := tmjson.Marshal(value) - if err != nil { - return RPCRequest{}, err +// ParamsToRequest constructs a new RPCRequest with the given ID, method, and parameters. +func ParamsToRequest(id jsonrpcid, method string, params interface{}) (RPCRequest, error) { + var payload json.RawMessage + var err error + switch t := params.(type) { + case map[string]interface{}: + // TODO(creachadair): This special case preserves existing behavior that + // relies on the custom JSON encoding library. Remove it once that + // requirement has been removed. + paramsMap := make(map[string]json.RawMessage, len(t)) + for name, value := range t { + valueJSON, err := tmjson.Marshal(value) + if err != nil { + return RPCRequest{}, err + } + paramsMap[name] = valueJSON } - paramsMap[name] = valueJSON + payload, err = json.Marshal(paramsMap) + default: + payload, err = json.Marshal(params) } - - payload, err := json.Marshal(paramsMap) if err != nil { return RPCRequest{}, err } diff --git a/rpc/test/helpers.go b/rpc/test/helpers.go index b7db50f6c..42f78c01f 100644 --- a/rpc/test/helpers.go +++ b/rpc/test/helpers.go @@ -32,7 +32,7 @@ func waitForRPC(ctx context.Context, conf *config.Config) { } result := new(coretypes.ResultStatus) for { - _, err := client.Call(ctx, "status", map[string]interface{}{}, result) + err := client.Call(ctx, "status", map[string]interface{}{}, result) if err == nil { return } From 2f858f14485ebc3b718d74ae3e6ce5967ce3f6b7 Mon Sep 17 00:00:00 2001 From: Kene <48869444+spaceCh1mp@users.noreply.github.com> Date: Tue, 11 Jan 2022 14:07:49 +0100 Subject: [PATCH 11/27] node: new concrete type for seed node implementation (#7521) Defines a different concrete type that satisfies the service interface for a seed node. update the seed node unit test to assert the new type. Fixes #6775 --- CHANGELOG_PENDING.md | 1 + node/node.go | 132 +++++++++++++++++++++++++++++++++---------- node/node_test.go | 2 +- 3 files changed, 105 insertions(+), 30 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 099e6fcf0..b08af302e 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -51,6 +51,7 @@ Special thanks to external contributors on this release: - [internal/protoio] \#7325 Optimized `MarshalDelimited` by inlining the common case and using a `sync.Pool` in the worst case. (@odeke-em) - [pubsub] \#7319 Performance improvements for the event query API (@creachadair) +- [node] \#7521 Define concrete type for seed node implementation (@spacech1mp) ### BUG FIXES diff --git a/node/node.go b/node/node.go index daf256104..e2951f83c 100644 --- a/node/node.go +++ b/node/node.go @@ -82,6 +82,26 @@ type nodeImpl struct { prometheusSrv *http.Server } +type seedNodeImpl struct { + service.BaseService + logger log.Logger + + // config + config *config.Config + genesisDoc *types.GenesisDoc // initial validator set + + // network + peerManager *p2p.PeerManager + router *p2p.Router + nodeInfo types.NodeInfo + nodeKey types.NodeKey // our node privkey + isListening bool + + // services + pexReactor service.Service // for exchanging peer addresses + shutdownOps closer +} + // newDefaultNode returns a Tendermint node with default settings for the // PrivValidator, ClientCreator, GenesisDoc, and DBProvider. // It implements NodeProvider. @@ -493,7 +513,7 @@ func makeSeedNode( return nil, combineCloseError(err, closer) } - node := &nodeImpl{ + node := &seedNodeImpl{ config: cfg, logger: logger, genesisDoc: genDoc, @@ -512,6 +532,68 @@ func makeSeedNode( return node, nil } +// OnStart starts the Seed Node. It implements service.Service. +func (n *seedNodeImpl) OnStart(ctx context.Context) error { + if n.config.RPC.PprofListenAddress != "" { + rpcCtx, rpcCancel := context.WithCancel(ctx) + srv := &http.Server{Addr: n.config.RPC.PprofListenAddress, Handler: nil} + go func() { + select { + case <-ctx.Done(): + sctx, scancel := context.WithTimeout(context.Background(), time.Second) + defer scancel() + _ = srv.Shutdown(sctx) + case <-rpcCtx.Done(): + } + }() + + go func() { + n.logger.Info("Starting pprof server", "laddr", n.config.RPC.PprofListenAddress) + + if err := srv.ListenAndServe(); err != nil { + n.logger.Error("pprof server error", "err", err) + rpcCancel() + } + }() + } + + now := tmtime.Now() + genTime := n.genesisDoc.GenesisTime + if genTime.After(now) { + n.logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime) + time.Sleep(genTime.Sub(now)) + } + + // Start the transport. + if err := n.router.Start(ctx); err != nil { + return err + } + n.isListening = true + + if n.config.P2P.PexReactor { + if err := n.pexReactor.Start(ctx); err != nil { + return err + } + } + + return nil +} + +// OnStop stops the Seed Node. It implements service.Service. +func (n *seedNodeImpl) OnStop() { + n.logger.Info("Stopping Node") + + n.pexReactor.Wait() + n.router.Wait() + n.isListening = false + + if err := n.shutdownOps(); err != nil { + if strings.TrimSpace(err.Error()) != "" { + n.logger.Error("problem shutting down additional services", "err", err) + } + } +} + // OnStart starts the Node. It implements service.Service. func (n *nodeImpl) OnStart(ctx context.Context) error { if n.config.RPC.PprofListenAddress != "" { @@ -546,7 +628,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { // Start the RPC server before the P2P server // so we can eg. receive txs for the first block - if n.config.RPC.ListenAddress != "" && n.config.Mode != config.ModeSeed { + if n.config.RPC.ListenAddress != "" { listeners, err := n.startRPC(ctx) if err != nil { return err @@ -564,30 +646,24 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { } n.isListening = true - if n.config.Mode != config.ModeSeed { - if err := n.bcReactor.Start(ctx); err != nil { - return err - } + if err := n.bcReactor.Start(ctx); err != nil { + return err + } - // Start the real consensus reactor separately since the switch uses the shim. - if err := n.consensusReactor.Start(ctx); err != nil { - return err - } + if err := n.consensusReactor.Start(ctx); err != nil { + return err + } - // Start the real state sync reactor separately since the switch uses the shim. - if err := n.stateSyncReactor.Start(ctx); err != nil { - return err - } + if err := n.stateSyncReactor.Start(ctx); err != nil { + return err + } - // Start the real mempool reactor separately since the switch uses the shim. - if err := n.mempoolReactor.Start(ctx); err != nil { - return err - } + if err := n.mempoolReactor.Start(ctx); err != nil { + return err + } - // Start the real evidence reactor separately since the switch uses the shim. - if err := n.evidenceReactor.Start(ctx); err != nil { - return err - } + if err := n.evidenceReactor.Start(ctx); err != nil { + return err } if n.config.P2P.PexReactor { @@ -686,13 +762,11 @@ func (n *nodeImpl) OnStop() { } } - if n.config.Mode != config.ModeSeed { - n.bcReactor.Wait() - n.consensusReactor.Wait() - n.stateSyncReactor.Wait() - n.mempoolReactor.Wait() - n.evidenceReactor.Wait() - } + n.bcReactor.Wait() + n.consensusReactor.Wait() + n.stateSyncReactor.Wait() + n.mempoolReactor.Wait() + n.evidenceReactor.Wait() n.pexReactor.Wait() n.router.Wait() n.isListening = false diff --git a/node/node_test.go b/node/node_test.go index 4abc3aca7..e07272673 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -556,7 +556,7 @@ func TestNodeNewSeedNode(t *testing.T) { t.Cleanup(ns.Wait) require.NoError(t, err) - n, ok := ns.(*nodeImpl) + n, ok := ns.(*seedNodeImpl) require.True(t, ok) err = n.Start(ctx) From 7f8b75e1ee6bbd838d64923dab1a7b271cc727aa Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Tue, 11 Jan 2022 06:37:38 -0800 Subject: [PATCH 12/27] rpc: replace anonymous arguments with structured types (#7552) Instead of using anonymous maps, define tagged struct types for JSON argument encoding. This allows us to have the encoding rules we want without tmjson. This commit handles the "easy" cases. BroadcastEvidence is omitted here, because it depends on the interface encoding rules from tmjson. I will address that in a forthcoming change. --- rpc/client/http/http.go | 153 +++++++++++++------------------------ rpc/client/http/request.go | 59 ++++++++++++++ 2 files changed, 110 insertions(+), 102 deletions(-) create mode 100644 rpc/client/http/request.go diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index de4269179..7dd6abb76 100644 --- a/rpc/client/http/http.go +++ b/rpc/client/http/http.go @@ -203,7 +203,7 @@ func (b *BatchHTTP) Count() int { func (c *baseRPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, error) { result := new(coretypes.ResultStatus) - if err := c.caller.Call(ctx, "status", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "status", nil, result); err != nil { return nil, err } return result, nil @@ -211,7 +211,7 @@ func (c *baseRPCClient) Status(ctx context.Context) (*coretypes.ResultStatus, er func (c *baseRPCClient) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { result := new(coretypes.ResultABCIInfo) - if err := c.caller.Call(ctx, "abci_info", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "abci_info", nil, result); err != nil { return nil, err } return result, nil @@ -231,9 +231,12 @@ func (c *baseRPCClient) ABCIQueryWithOptions( data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { result := new(coretypes.ResultABCIQuery) - if err := c.caller.Call(ctx, "abci_query", - map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove}, - result); err != nil { + if err := c.caller.Call(ctx, "abci_query", abciQueryArgs{ + Path: path, + Data: data, + Height: opts.Height, + Prove: opts.Prove, + }, result); err != nil { return nil, err } return result, nil @@ -244,7 +247,7 @@ func (c *baseRPCClient) BroadcastTxCommit( tx types.Tx, ) (*coretypes.ResultBroadcastTxCommit, error) { result := new(coretypes.ResultBroadcastTxCommit) - if err := c.caller.Call(ctx, "broadcast_tx_commit", map[string]interface{}{"tx": tx}, result); err != nil { + if err := c.caller.Call(ctx, "broadcast_tx_commit", txArgs{Tx: tx}, result); err != nil { return nil, err } return result, nil @@ -270,7 +273,7 @@ func (c *baseRPCClient) broadcastTX( tx types.Tx, ) (*coretypes.ResultBroadcastTx, error) { result := new(coretypes.ResultBroadcastTx) - if err := c.caller.Call(ctx, route, map[string]interface{}{"tx": tx}, result); err != nil { + if err := c.caller.Call(ctx, route, txArgs{Tx: tx}, result); err != nil { return nil, err } return result, nil @@ -281,11 +284,8 @@ func (c *baseRPCClient) UnconfirmedTxs( limit *int, ) (*coretypes.ResultUnconfirmedTxs, error) { result := new(coretypes.ResultUnconfirmedTxs) - params := make(map[string]interface{}) - if limit != nil { - params["limit"] = limit - } - if err := c.caller.Call(ctx, "unconfirmed_txs", params, result); err != nil { + + if err := c.caller.Call(ctx, "unconfirmed_txs", unconfirmedArgs{Limit: limit}, result); err != nil { return nil, err } return result, nil @@ -293,7 +293,7 @@ func (c *baseRPCClient) UnconfirmedTxs( func (c *baseRPCClient) NumUnconfirmedTxs(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) { result := new(coretypes.ResultUnconfirmedTxs) - if err := c.caller.Call(ctx, "num_unconfirmed_txs", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "num_unconfirmed_txs", nil, result); err != nil { return nil, err } return result, nil @@ -301,14 +301,14 @@ func (c *baseRPCClient) NumUnconfirmedTxs(ctx context.Context) (*coretypes.Resul func (c *baseRPCClient) CheckTx(ctx context.Context, tx types.Tx) (*coretypes.ResultCheckTx, error) { result := new(coretypes.ResultCheckTx) - if err := c.caller.Call(ctx, "check_tx", map[string]interface{}{"tx": tx}, result); err != nil { + if err := c.caller.Call(ctx, "check_tx", txArgs{Tx: tx}, result); err != nil { return nil, err } return result, nil } func (c *baseRPCClient) RemoveTx(ctx context.Context, txKey types.TxKey) error { - if err := c.caller.Call(ctx, "remove_tx", map[string]interface{}{"tx_key": txKey}, nil); err != nil { + if err := c.caller.Call(ctx, "remove_tx", txKeyArgs{TxKey: txKey[:]}, nil); err != nil { return err } return nil @@ -316,7 +316,7 @@ func (c *baseRPCClient) RemoveTx(ctx context.Context, txKey types.TxKey) error { func (c *baseRPCClient) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, error) { result := new(coretypes.ResultNetInfo) - if err := c.caller.Call(ctx, "net_info", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "net_info", nil, result); err != nil { return nil, err } return result, nil @@ -324,7 +324,7 @@ func (c *baseRPCClient) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, func (c *baseRPCClient) DumpConsensusState(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) { result := new(coretypes.ResultDumpConsensusState) - if err := c.caller.Call(ctx, "dump_consensus_state", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "dump_consensus_state", nil, result); err != nil { return nil, err } return result, nil @@ -332,7 +332,7 @@ func (c *baseRPCClient) DumpConsensusState(ctx context.Context) (*coretypes.Resu func (c *baseRPCClient) ConsensusState(ctx context.Context) (*coretypes.ResultConsensusState, error) { result := new(coretypes.ResultConsensusState) - if err := c.caller.Call(ctx, "consensus_state", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "consensus_state", nil, result); err != nil { return nil, err } return result, nil @@ -343,11 +343,7 @@ func (c *baseRPCClient) ConsensusParams( height *int64, ) (*coretypes.ResultConsensusParams, error) { result := new(coretypes.ResultConsensusParams) - params := make(map[string]interface{}) - if height != nil { - params["height"] = height - } - if err := c.caller.Call(ctx, "consensus_params", params, result); err != nil { + if err := c.caller.Call(ctx, "consensus_params", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -355,7 +351,7 @@ func (c *baseRPCClient) ConsensusParams( func (c *baseRPCClient) Health(ctx context.Context) (*coretypes.ResultHealth, error) { result := new(coretypes.ResultHealth) - if err := c.caller.Call(ctx, "health", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "health", nil, result); err != nil { return nil, err } return result, nil @@ -367,9 +363,10 @@ func (c *baseRPCClient) BlockchainInfo( maxHeight int64, ) (*coretypes.ResultBlockchainInfo, error) { result := new(coretypes.ResultBlockchainInfo) - if err := c.caller.Call(ctx, "blockchain", - map[string]interface{}{"minHeight": minHeight, "maxHeight": maxHeight}, - result); err != nil { + if err := c.caller.Call(ctx, "blockchain", blockchainInfoArgs{ + MinHeight: minHeight, + MaxHeight: maxHeight, + }, result); err != nil { return nil, err } return result, nil @@ -377,7 +374,7 @@ func (c *baseRPCClient) BlockchainInfo( func (c *baseRPCClient) Genesis(ctx context.Context) (*coretypes.ResultGenesis, error) { result := new(coretypes.ResultGenesis) - if err := c.caller.Call(ctx, "genesis", map[string]interface{}{}, result); err != nil { + if err := c.caller.Call(ctx, "genesis", nil, result); err != nil { return nil, err } return result, nil @@ -385,7 +382,7 @@ func (c *baseRPCClient) Genesis(ctx context.Context) (*coretypes.ResultGenesis, func (c *baseRPCClient) GenesisChunked(ctx context.Context, id uint) (*coretypes.ResultGenesisChunk, error) { result := new(coretypes.ResultGenesisChunk) - if err := c.caller.Call(ctx, "genesis_chunked", map[string]interface{}{"chunk": id}, result); err != nil { + if err := c.caller.Call(ctx, "genesis_chunked", genesisChunkArgs{Chunk: id}, result); err != nil { return nil, err } return result, nil @@ -393,11 +390,7 @@ func (c *baseRPCClient) GenesisChunked(ctx context.Context, id uint) (*coretypes func (c *baseRPCClient) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { result := new(coretypes.ResultBlock) - params := make(map[string]interface{}) - if height != nil { - params["height"] = height - } - if err := c.caller.Call(ctx, "block", params, result); err != nil { + if err := c.caller.Call(ctx, "block", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -405,10 +398,7 @@ func (c *baseRPCClient) Block(ctx context.Context, height *int64) (*coretypes.Re func (c *baseRPCClient) BlockByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { result := new(coretypes.ResultBlock) - params := map[string]interface{}{ - "hash": hash, - } - if err := c.caller.Call(ctx, "block_by_hash", params, result); err != nil { + if err := c.caller.Call(ctx, "block_by_hash", hashArgs{Hash: hash}, result); err != nil { return nil, err } return result, nil @@ -419,11 +409,7 @@ func (c *baseRPCClient) BlockResults( height *int64, ) (*coretypes.ResultBlockResults, error) { result := new(coretypes.ResultBlockResults) - params := make(map[string]interface{}) - if height != nil { - params["height"] = height - } - if err := c.caller.Call(ctx, "block_results", params, result); err != nil { + if err := c.caller.Call(ctx, "block_results", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -431,11 +417,7 @@ func (c *baseRPCClient) BlockResults( func (c *baseRPCClient) Header(ctx context.Context, height *int64) (*coretypes.ResultHeader, error) { result := new(coretypes.ResultHeader) - params := make(map[string]interface{}) - if height != nil { - params["height"] = height - } - if err := c.caller.Call(ctx, "header", params, result); err != nil { + if err := c.caller.Call(ctx, "header", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -443,10 +425,7 @@ func (c *baseRPCClient) Header(ctx context.Context, height *int64) (*coretypes.R func (c *baseRPCClient) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) { result := new(coretypes.ResultHeader) - params := map[string]interface{}{ - "hash": hash, - } - if err := c.caller.Call(ctx, "header_by_hash", params, result); err != nil { + if err := c.caller.Call(ctx, "header_by_hash", hashArgs{Hash: hash}, result); err != nil { return nil, err } return result, nil @@ -454,11 +433,7 @@ func (c *baseRPCClient) HeaderByHash(ctx context.Context, hash bytes.HexBytes) ( func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { result := new(coretypes.ResultCommit) - params := make(map[string]interface{}) - if height != nil { - params["height"] = height - } - if err := c.caller.Call(ctx, "commit", params, result); err != nil { + if err := c.caller.Call(ctx, "commit", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -466,11 +441,7 @@ func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*coretypes.R func (c *baseRPCClient) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { result := new(coretypes.ResultTx) - params := map[string]interface{}{ - "hash": hash, - "prove": prove, - } - if err := c.caller.Call(ctx, "tx", params, result); err != nil { + if err := c.caller.Call(ctx, "tx", hashArgs{Hash: hash, Prove: prove}, result); err != nil { return nil, err } return result, nil @@ -484,22 +455,14 @@ func (c *baseRPCClient) TxSearch( perPage *int, orderBy string, ) (*coretypes.ResultTxSearch, error) { - result := new(coretypes.ResultTxSearch) - params := map[string]interface{}{ - "query": query, - "prove": prove, - "order_by": orderBy, - } - - if page != nil { - params["page"] = page - } - if perPage != nil { - params["per_page"] = perPage - } - - if err := c.caller.Call(ctx, "tx_search", params, result); err != nil { + if err := c.caller.Call(ctx, "tx_search", searchArgs{ + Query: query, + Prove: prove, + OrderBy: orderBy, + Page: page, + PerPage: perPage, + }, result); err != nil { return nil, err } @@ -512,21 +475,13 @@ func (c *baseRPCClient) BlockSearch( page, perPage *int, orderBy string, ) (*coretypes.ResultBlockSearch, error) { - result := new(coretypes.ResultBlockSearch) - params := map[string]interface{}{ - "query": query, - "order_by": orderBy, - } - - if page != nil { - params["page"] = page - } - if perPage != nil { - params["per_page"] = perPage - } - - if err := c.caller.Call(ctx, "block_search", params, result); err != nil { + if err := c.caller.Call(ctx, "block_search", searchArgs{ + Query: query, + OrderBy: orderBy, + Page: page, + PerPage: perPage, + }, result); err != nil { return nil, err } @@ -540,17 +495,11 @@ func (c *baseRPCClient) Validators( perPage *int, ) (*coretypes.ResultValidators, error) { result := new(coretypes.ResultValidators) - params := make(map[string]interface{}) - if page != nil { - params["page"] = page - } - if perPage != nil { - params["per_page"] = perPage - } - if height != nil { - params["height"] = height - } - if err := c.caller.Call(ctx, "validators", params, result); err != nil { + if err := c.caller.Call(ctx, "validators", validatorArgs{ + Height: height, + Page: page, + PerPage: perPage, + }, result); err != nil { return nil, err } return result, nil diff --git a/rpc/client/http/request.go b/rpc/client/http/request.go new file mode 100644 index 000000000..5d1d3db5b --- /dev/null +++ b/rpc/client/http/request.go @@ -0,0 +1,59 @@ +package http + +// The types in this file define the JSON encoding for RPC method parameters +// from the client to the server. + +import ( + "github.com/tendermint/tendermint/libs/bytes" +) + +type abciQueryArgs struct { + Path string `json:"path"` + Data bytes.HexBytes `json:"data"` + Height int64 `json:"height,string"` + Prove bool `json:"prove"` +} + +type txArgs struct { + Tx []byte `json:"tx"` +} + +type txKeyArgs struct { + TxKey []byte `json:"tx_key"` +} + +type unconfirmedArgs struct { + Limit *int `json:"limit,string,omitempty"` +} + +type heightArgs struct { + Height *int64 `json:"height,string,omitempty"` +} + +type hashArgs struct { + Hash bytes.HexBytes `json:"hash"` + Prove bool `json:"prove,omitempty"` +} + +type blockchainInfoArgs struct { + MinHeight int64 `json:"minHeight,string"` + MaxHeight int64 `json:"maxHeight,string"` +} + +type genesisChunkArgs struct { + Chunk uint `json:"chunk,string"` +} + +type searchArgs struct { + Query string `json:"query"` + Prove bool `json:"prove,omitempty"` + OrderBy string `json:"order_by,omitempty"` + Page *int `json:"page,string,omitempty"` + PerPage *int `json:"per_page,string,omitempty"` +} + +type validatorArgs struct { + Height *int64 `json:"height,string,omitempty"` + Page *int `json:"page,string,omitempty"` + PerPage *int `json:"per_page,string,omitempty"` +} From 5bf1bdcfb4a2f1cc807a1a972cc564f9d10d0d59 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 11 Jan 2022 12:56:52 -0500 Subject: [PATCH 13/27] reactors: skip log on some routine cancels (#7556) --- cmd/priv_val_server/main.go | 1 - internal/blocksync/reactor.go | 1 - internal/consensus/reactor.go | 1 - internal/consensus/ticker.go | 2 -- internal/evidence/reactor.go | 1 - internal/mempool/reactor.go | 1 - internal/p2p/conn/connection.go | 5 ----- internal/p2p/pex/reactor.go | 2 -- internal/p2p/router.go | 9 --------- internal/statesync/reactor.go | 1 - rpc/jsonrpc/client/ws_client.go | 2 -- 11 files changed, 26 deletions(-) diff --git a/cmd/priv_val_server/main.go b/cmd/priv_val_server/main.go index baacadf1e..bdd5091d9 100644 --- a/cmd/priv_val_server/main.go +++ b/cmd/priv_val_server/main.go @@ -138,7 +138,6 @@ func main() { defer opcancel() go func() { <-opctx.Done() - logger.Debug("SignerServer: calling Close") if *prometheusAddr != "" { ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() diff --git a/internal/blocksync/reactor.go b/internal/blocksync/reactor.go index b3142d953..a67b50874 100644 --- a/internal/blocksync/reactor.go +++ b/internal/blocksync/reactor.go @@ -354,7 +354,6 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { for { select { case <-ctx.Done(): - r.logger.Debug("stopped listening on peer updates channel; closing...") return case peerUpdate := <-r.peerUpdates.Updates(): r.processPeerUpdate(peerUpdate) diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index 6c1bbae5f..127b175bc 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -1455,7 +1455,6 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { for { select { case <-ctx.Done(): - r.logger.Debug("stopped listening on peer updates channel; closing...") return case peerUpdate := <-r.peerUpdates.Updates(): r.processPeerUpdate(ctx, peerUpdate) diff --git a/internal/consensus/ticker.go b/internal/consensus/ticker.go index 686ca6b7a..26570b734 100644 --- a/internal/consensus/ticker.go +++ b/internal/consensus/ticker.go @@ -81,7 +81,6 @@ func (t *timeoutTicker) stopTimer() { select { case <-t.timer.C: default: - t.logger.Debug("Timer already stopped") } } } @@ -90,7 +89,6 @@ func (t *timeoutTicker) stopTimer() { // timers are interupted and replaced by new ticks from later steps // timeouts of 0 on the tickChan will be immediately relayed to the tockChan func (t *timeoutTicker) timeoutRoutine(ctx context.Context) { - t.logger.Debug("Starting timeout routine") var ti timeoutInfo for { select { diff --git a/internal/evidence/reactor.go b/internal/evidence/reactor.go index 8fb7bece5..2a6ed4ff9 100644 --- a/internal/evidence/reactor.go +++ b/internal/evidence/reactor.go @@ -255,7 +255,6 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { case peerUpdate := <-r.peerUpdates.Updates(): r.processPeerUpdate(ctx, peerUpdate) case <-ctx.Done(): - r.logger.Debug("stopped listening on peer updates channel; closing...") return } } diff --git a/internal/mempool/reactor.go b/internal/mempool/reactor.go index d1d027bd8..7ef80aecd 100644 --- a/internal/mempool/reactor.go +++ b/internal/mempool/reactor.go @@ -281,7 +281,6 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { for { select { case <-ctx.Done(): - r.logger.Debug("stopped listening on peer updates channel; closing...") return case peerUpdate := <-r.peerUpdates.Updates(): r.processPeerUpdate(ctx, peerUpdate) diff --git a/internal/p2p/conn/connection.go b/internal/p2p/conn/connection.go index 04ecfc92c..ba9e9a2e3 100644 --- a/internal/p2p/conn/connection.go +++ b/internal/p2p/conn/connection.go @@ -353,7 +353,6 @@ FOR_LOOP: channel.updateStats() } case <-c.pingTimer.C: - c.logger.Debug("Send Ping") _n, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPing{})) if err != nil { c.logger.Error("Failed to send PacketPing", "err", err) @@ -370,13 +369,11 @@ FOR_LOOP: c.flush() case timeout := <-c.pongTimeoutCh: if timeout { - c.logger.Debug("Pong timeout") err = errors.New("pong timeout") } else { c.stopPongTimer() } case <-c.pong: - c.logger.Debug("Send Pong") _n, err = protoWriter.WriteMsg(mustWrapPacket(&tmp2p.PacketPong{})) if err != nil { c.logger.Error("Failed to send PacketPong", "err", err) @@ -528,14 +525,12 @@ FOR_LOOP: case *tmp2p.Packet_PacketPing: // TODO: prevent abuse, as they cause flush()'s. // https://github.com/tendermint/tendermint/issues/1190 - c.logger.Debug("Receive Ping") select { case c.pong <- struct{}{}: default: // never block } case *tmp2p.Packet_PacketPong: - c.logger.Debug("Receive Pong") select { case c.pongTimeoutCh <- false: default: diff --git a/internal/p2p/pex/reactor.go b/internal/p2p/pex/reactor.go index b1f33081a..82a3e2ca8 100644 --- a/internal/p2p/pex/reactor.go +++ b/internal/p2p/pex/reactor.go @@ -181,7 +181,6 @@ func (r *Reactor) processPexCh(ctx context.Context) { select { case <-ctx.Done(): - r.logger.Debug("stopped listening on PEX channel; closing...") return // outbound requests for new peers @@ -215,7 +214,6 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { for { select { case <-ctx.Done(): - r.logger.Debug("stopped listening on peer updates channel; closing...") return case peerUpdate := <-r.peerUpdates.Updates(): r.processPeerUpdate(peerUpdate) diff --git a/internal/p2p/router.go b/internal/p2p/router.go index 6c6bf78ed..c60fe30a5 100644 --- a/internal/p2p/router.go +++ b/internal/p2p/router.go @@ -472,8 +472,6 @@ func (r *Router) dialSleep(ctx context.Context) { // acceptPeers accepts inbound connections from peers on the given transport, // and spawns goroutines that route messages to/from them. func (r *Router) acceptPeers(ctx context.Context, transport Transport) { - r.logger.Debug("starting accept routine", "transport", transport) - for { conn, err := transport.Accept(ctx) switch err { @@ -555,8 +553,6 @@ func (r *Router) openConnection(ctx context.Context, conn Connection) { // dialPeers maintains outbound connections to peers by dialing them. func (r *Router) dialPeers(ctx context.Context) { - r.logger.Debug("starting dial routine") - addresses := make(chan NodeAddress) wg := &sync.WaitGroup{} @@ -587,7 +583,6 @@ LOOP: address, err := r.peerManager.DialNext(ctx) switch { case errors.Is(err, context.Canceled): - r.logger.Debug("stopping dial routine") break LOOP case err != nil: r.logger.Error("failed to find next peer to dial", "err", err) @@ -917,16 +912,12 @@ func (r *Router) sendPeer(ctx context.Context, peerID types.NodeID, conn Connect // evictPeers evicts connected peers as requested by the peer manager. func (r *Router) evictPeers(ctx context.Context) { - r.logger.Debug("starting evict routine") - for { peerID, err := r.peerManager.EvictNext(ctx) switch { case errors.Is(err, context.Canceled): - r.logger.Debug("stopping evict routine") return - case err != nil: r.logger.Error("failed to find next peer to evict", "err", err) return diff --git a/internal/statesync/reactor.go b/internal/statesync/reactor.go index b9113cc21..25b30d9ad 100644 --- a/internal/statesync/reactor.go +++ b/internal/statesync/reactor.go @@ -887,7 +887,6 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { for { select { case <-ctx.Done(): - r.logger.Debug("stopped listening on peer updates channel; closing...") return case peerUpdate := <-r.peerUpdates.Updates(): r.processPeerUpdate(ctx, peerUpdate) diff --git a/rpc/jsonrpc/client/ws_client.go b/rpc/jsonrpc/client/ws_client.go index 80520e2a3..8be59737a 100644 --- a/rpc/jsonrpc/client/ws_client.go +++ b/rpc/jsonrpc/client/ws_client.go @@ -411,7 +411,6 @@ func (c *WSClient) writeRoutine(ctx context.Context) { c.mtx.Lock() c.sentLastPingAt = time.Now() c.mtx.Unlock() - c.Logger.Debug("sent ping") case <-c.readRoutineQuit: return case <-ctx.Done(): @@ -445,7 +444,6 @@ func (c *WSClient) readRoutine(ctx context.Context) { c.mtx.RUnlock() c.PingPongLatencyTimer.UpdateSince(t) - c.Logger.Debug("got pong") return nil }) From a4d0a431003b21751b3011908a08badafe890f72 Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Tue, 11 Jan 2022 11:04:55 -0800 Subject: [PATCH 14/27] rpc: refactor the HTTP POST handler (#7555) No functional changes. - Pull out a some helper code to simplify the control flow within the body of the HTTP request handler. - Front-load the URL path check so it does not get repeated for each request. --- rpc/jsonrpc/server/http_json_handler.go | 165 +++++++++++++----------- 1 file changed, 88 insertions(+), 77 deletions(-) diff --git a/rpc/jsonrpc/server/http_json_handler.go b/rpc/jsonrpc/server/http_json_handler.go index dabeee074..879a58df9 100644 --- a/rpc/jsonrpc/server/http_json_handler.go +++ b/rpc/jsonrpc/server/http_json_handler.go @@ -20,127 +20,103 @@ import ( // jsonrpc calls grab the given method's function info and runs reflect.Call func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - b, err := io.ReadAll(r.Body) - if err != nil { - res := rpctypes.RPCInvalidRequestError(nil, - fmt.Errorf("error reading request body: %w", err), - ) - if wErr := WriteRPCResponseHTTPError(w, res); wErr != nil { - logger.Error("failed to write response", "res", res, "err", wErr) + return func(w http.ResponseWriter, hreq *http.Request) { + fail := func(res rpctypes.RPCResponse) { + if err := WriteRPCResponseHTTPError(w, res); err != nil { + logger.Error("Failed writing error response", "res", res, "err", err) } + } + + // For POST requests, reject a non-root URL path. This should not happen + // in the standard configuration, since the wrapper checks the path. + if hreq.URL.Path != "/" { + fail(rpctypes.RPCInvalidRequestError(nil, fmt.Errorf("invalid path: %q", hreq.URL.Path))) + return + } + + b, err := io.ReadAll(hreq.Body) + if err != nil { + fail(rpctypes.RPCInvalidRequestError(nil, fmt.Errorf("reading request body: %w", err))) return } // if its an empty request (like from a browser), just display a list of // functions if len(b) == 0 { - writeListOfEndpoints(w, r, funcMap) + writeListOfEndpoints(w, hreq, funcMap) return } - // first try to unmarshal the incoming request as an array of RPC requests - var ( - requests []rpctypes.RPCRequest - responses []rpctypes.RPCResponse - ) - if err := json.Unmarshal(b, &requests); err != nil { - // next, try to unmarshal as a single request - var request rpctypes.RPCRequest - if err := json.Unmarshal(b, &request); err != nil { - res := rpctypes.RPCParseError(fmt.Errorf("error unmarshaling request: %w", err)) - if wErr := WriteRPCResponseHTTPError(w, res); wErr != nil { - logger.Error("failed to write response", "res", res, "err", wErr) - } - return - } - requests = []rpctypes.RPCRequest{request} + requests, err := parseRequests(b) + if err != nil { + fail(rpctypes.RPCParseError(fmt.Errorf("decoding request: %w", err))) + return } // Set the default response cache to true unless // 1. Any RPC request rrror. // 2. Any RPC request doesn't allow to be cached. // 3. Any RPC request has the height argument and the value is 0 (the default). - var c = true - for _, request := range requests { - request := request + var responses []rpctypes.RPCResponse + mayCache := true + for _, req := range requests { + // Ignore notifications, which this service does not support. + if req.ID == nil { + logger.Debug("Ignoring notification", "req", req) + continue + } - // A Notification is a Request object without an "id" member. - // The Server MUST NOT reply to a Notification, including those that are within a batch request. - if request.ID == nil { - logger.Debug( - "HTTPJSONRPC received a notification, skipping... (please send a non-empty ID if you want to call a method)", - "req", request, - ) - continue - } - if len(r.URL.Path) > 1 { - responses = append( - responses, - rpctypes.RPCInvalidRequestError(request.ID, fmt.Errorf("path %s is invalid", r.URL.Path)), - ) - c = false - continue - } - rpcFunc, ok := funcMap[request.Method] + rpcFunc, ok := funcMap[req.Method] if !ok || rpcFunc.ws { - responses = append(responses, rpctypes.RPCMethodNotFoundError(request.ID)) - c = false + responses = append(responses, rpctypes.RPCMethodNotFoundError(req.ID)) + mayCache = false continue } - ctx := &rpctypes.Context{JSONReq: &request, HTTPReq: r} - args := []reflect.Value{reflect.ValueOf(ctx)} - if len(request.Params) > 0 { - fnArgs, err := jsonParamsToArgs(rpcFunc, request.Params) - if err != nil { - responses = append( - responses, - rpctypes.RPCInvalidParamsError(request.ID, fmt.Errorf("error converting json params to arguments: %w", err)), - ) - c = false - continue - } - args = append(args, fnArgs...) - + if !rpcFunc.cache { + mayCache = false } - if hasDefaultHeight(request, args) { - c = false + args, err := parseParams(rpcFunc, hreq, req) + if err != nil { + responses = append(responses, rpctypes.RPCInvalidParamsError( + req.ID, fmt.Errorf("converting JSON parameters: %w", err))) + mayCache = false + continue + } + + if hasDefaultHeight(req, args) { + mayCache = false } returns := rpcFunc.f.Call(args) - logger.Debug("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns) + logger.Debug("HTTPJSONRPC", "method", req.Method, "args", args, "returns", returns) result, err := unreflectResult(returns) switch e := err.(type) { // if no error then return a success response case nil: - responses = append(responses, rpctypes.NewRPCSuccessResponse(request.ID, result)) + responses = append(responses, rpctypes.NewRPCSuccessResponse(req.ID, result)) // if this already of type RPC error then forward that error case *rpctypes.RPCError: - responses = append(responses, rpctypes.NewRPCErrorResponse(request.ID, e.Code, e.Message, e.Data)) - c = false + responses = append(responses, rpctypes.NewRPCErrorResponse(req.ID, e.Code, e.Message, e.Data)) + mayCache = false default: // we need to unwrap the error and parse it accordingly switch errors.Unwrap(err) { // check if the error was due to an invald request case coretypes.ErrZeroOrNegativeHeight, coretypes.ErrZeroOrNegativePerPage, coretypes.ErrPageOutOfRange, coretypes.ErrInvalidRequest: - responses = append(responses, rpctypes.RPCInvalidRequestError(request.ID, err)) - c = false + responses = append(responses, rpctypes.RPCInvalidRequestError(req.ID, err)) + mayCache = false // lastly default all remaining errors as internal errors default: // includes ctypes.ErrHeightNotAvailable and ctypes.ErrHeightExceedsChainHead - responses = append(responses, rpctypes.RPCInternalError(request.ID, err)) - c = false + responses = append(responses, rpctypes.RPCInternalError(req.ID, err)) + mayCache = false } } - - if c && !rpcFunc.cache { - c = false - } } if len(responses) > 0 { - if wErr := WriteRPCResponseHTTP(w, c, responses...); wErr != nil { + if wErr := WriteRPCResponseHTTP(w, mayCache, responses...); wErr != nil { logger.Error("failed to write responses", "err", wErr) } } @@ -160,6 +136,24 @@ func handleInvalidJSONRPCPaths(next http.HandlerFunc) http.HandlerFunc { } } +// parseRequests parses a JSON-RPC request or request batch from data. +func parseRequests(data []byte) ([]rpctypes.RPCRequest, error) { + var reqs []rpctypes.RPCRequest + var err error + + isArray := bytes.HasPrefix(bytes.TrimSpace(data), []byte("[")) + if isArray { + err = json.Unmarshal(data, &reqs) + } else { + reqs = append(reqs, rpctypes.RPCRequest{}) + err = json.Unmarshal(data, &reqs[0]) + } + if err != nil { + return nil, err + } + return reqs, nil +} + func mapParamsToArgs( rpcFunc *RPCFunc, params map[string]json.RawMessage, @@ -209,6 +203,23 @@ func arrayParamsToArgs( return values, nil } +// parseParams parses the JSON parameters of rpcReq into the arguments of fn, +// returning the corresponding argument values or an error. +func parseParams(fn *RPCFunc, httpReq *http.Request, rpcReq rpctypes.RPCRequest) ([]reflect.Value, error) { + args := []reflect.Value{reflect.ValueOf(&rpctypes.Context{ + JSONReq: &rpcReq, + HTTPReq: httpReq, + })} + if len(rpcReq.Params) == 0 { + return args, nil + } + fargs, err := jsonParamsToArgs(fn, rpcReq.Params) + if err != nil { + return nil, err + } + return append(args, fargs...), nil +} + // raw is unparsed json (from json.RawMessage) encoding either a map or an // array. // From 50ac52e28d9264a8ddc6b14ff1642cbe2b29b9e0 Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Tue, 11 Jan 2022 11:47:56 -0800 Subject: [PATCH 15/27] rpc: replace custom context-like argument with context.Context (#7559) * Rename rpctypes.Context to CallInfo. Add methods to attach and recover this value from a context.Context. * Rework RPC method handlers to accept "real" contexts. - Replace *rpctypes.Context arguments with context.Context. - Update usage of RPC context fields to use CallInfo. --- internal/rpc/core/abci.go | 11 +- internal/rpc/core/blocks.go | 20 +-- internal/rpc/core/blocks_test.go | 5 +- internal/rpc/core/consensus.go | 11 +- internal/rpc/core/dev.go | 5 +- internal/rpc/core/events.go | 25 +-- internal/rpc/core/evidence.go | 4 +- internal/rpc/core/health.go | 5 +- internal/rpc/core/mempool.go | 26 +-- internal/rpc/core/net.go | 8 +- internal/rpc/core/status.go | 4 +- internal/rpc/core/tx.go | 8 +- light/proxy/routes.go | 165 ++++++++++--------- light/rpc/client.go | 17 +- rpc/client/local/local.go | 63 ++++--- rpc/client/mock/client.go | 39 +++-- rpc/jsonrpc/jsonrpc_test.go | 11 +- rpc/jsonrpc/server/http_json_handler.go | 11 +- rpc/jsonrpc/server/http_json_handler_test.go | 5 +- rpc/jsonrpc/server/http_uri_handler.go | 2 +- rpc/jsonrpc/server/parse_test.go | 6 +- rpc/jsonrpc/server/ws_handler.go | 7 +- rpc/jsonrpc/server/ws_handler_test.go | 3 +- rpc/jsonrpc/test/main.go | 3 +- rpc/jsonrpc/types/types.go | 74 ++++----- 25 files changed, 270 insertions(+), 268 deletions(-) diff --git a/internal/rpc/core/abci.go b/internal/rpc/core/abci.go index 06c033050..783a78cb3 100644 --- a/internal/rpc/core/abci.go +++ b/internal/rpc/core/abci.go @@ -1,23 +1,24 @@ package core import ( + "context" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/internal/proxy" "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // ABCIQuery queries the application for some information. // More: https://docs.tendermint.com/master/rpc/#/ABCI/abci_query func (env *Environment) ABCIQuery( - ctx *rpctypes.Context, + ctx context.Context, path string, data bytes.HexBytes, height int64, prove bool, ) (*coretypes.ResultABCIQuery, error) { - resQuery, err := env.ProxyAppQuery.QuerySync(ctx.Context(), abci.RequestQuery{ + resQuery, err := env.ProxyAppQuery.QuerySync(ctx, abci.RequestQuery{ Path: path, Data: data, Height: height, @@ -32,8 +33,8 @@ func (env *Environment) ABCIQuery( // ABCIInfo gets some info about the application. // More: https://docs.tendermint.com/master/rpc/#/ABCI/abci_info -func (env *Environment) ABCIInfo(ctx *rpctypes.Context) (*coretypes.ResultABCIInfo, error) { - resInfo, err := env.ProxyAppQuery.InfoSync(ctx.Context(), proxy.RequestInfo) +func (env *Environment) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { + resInfo, err := env.ProxyAppQuery.InfoSync(ctx, proxy.RequestInfo) if err != nil { return nil, err } diff --git a/internal/rpc/core/blocks.go b/internal/rpc/core/blocks.go index 725a2f972..9f6c872ca 100644 --- a/internal/rpc/core/blocks.go +++ b/internal/rpc/core/blocks.go @@ -1,6 +1,7 @@ package core import ( + "context" "fmt" "sort" @@ -9,7 +10,6 @@ import ( "github.com/tendermint/tendermint/libs/bytes" tmmath "github.com/tendermint/tendermint/libs/math" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) @@ -24,7 +24,7 @@ import ( // // More: https://docs.tendermint.com/master/rpc/#/Info/blockchain func (env *Environment) BlockchainInfo( - ctx *rpctypes.Context, + ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) { const limit int64 = 20 @@ -92,7 +92,7 @@ func filterMinMax(base, height, min, max, limit int64) (int64, int64, error) { // Block gets block at a given height. // If no height is provided, it will fetch the latest block. // More: https://docs.tendermint.com/master/rpc/#/Info/block -func (env *Environment) Block(ctx *rpctypes.Context, heightPtr *int64) (*coretypes.ResultBlock, error) { +func (env *Environment) Block(ctx context.Context, heightPtr *int64) (*coretypes.ResultBlock, error) { height, err := env.getHeight(env.BlockStore.Height(), heightPtr) if err != nil { return nil, err @@ -109,7 +109,7 @@ func (env *Environment) Block(ctx *rpctypes.Context, heightPtr *int64) (*coretyp // BlockByHash gets block by hash. // More: https://docs.tendermint.com/master/rpc/#/Info/block_by_hash -func (env *Environment) BlockByHash(ctx *rpctypes.Context, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { +func (env *Environment) BlockByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { // N.B. The hash parameter is HexBytes so that the reflective parameter // decoding logic in the HTTP service will correctly translate from JSON. // See https://github.com/tendermint/tendermint/issues/6802 for context. @@ -126,7 +126,7 @@ func (env *Environment) BlockByHash(ctx *rpctypes.Context, hash bytes.HexBytes) // Header gets block header at a given height. // If no height is provided, it will fetch the latest header. // More: https://docs.tendermint.com/master/rpc/#/Info/header -func (env *Environment) Header(ctx *rpctypes.Context, heightPtr *int64) (*coretypes.ResultHeader, error) { +func (env *Environment) Header(ctx context.Context, heightPtr *int64) (*coretypes.ResultHeader, error) { height, err := env.getHeight(env.BlockStore.Height(), heightPtr) if err != nil { return nil, err @@ -142,7 +142,7 @@ func (env *Environment) Header(ctx *rpctypes.Context, heightPtr *int64) (*corety // HeaderByHash gets header by hash. // More: https://docs.tendermint.com/master/rpc/#/Info/header_by_hash -func (env *Environment) HeaderByHash(ctx *rpctypes.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) { +func (env *Environment) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) { // N.B. The hash parameter is HexBytes so that the reflective parameter // decoding logic in the HTTP service will correctly translate from JSON. // See https://github.com/tendermint/tendermint/issues/6802 for context. @@ -158,7 +158,7 @@ func (env *Environment) HeaderByHash(ctx *rpctypes.Context, hash bytes.HexBytes) // Commit gets block commit at a given height. // If no height is provided, it will fetch the commit for the latest block. // More: https://docs.tendermint.com/master/rpc/#/Info/commit -func (env *Environment) Commit(ctx *rpctypes.Context, heightPtr *int64) (*coretypes.ResultCommit, error) { +func (env *Environment) Commit(ctx context.Context, heightPtr *int64) (*coretypes.ResultCommit, error) { height, err := env.getHeight(env.BlockStore.Height(), heightPtr) if err != nil { return nil, err @@ -196,7 +196,7 @@ func (env *Environment) Commit(ctx *rpctypes.Context, heightPtr *int64) (*corety // Thus response.results.deliver_tx[5] is the results of executing // getBlock(h).Txs[5] // More: https://docs.tendermint.com/master/rpc/#/Info/block_results -func (env *Environment) BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*coretypes.ResultBlockResults, error) { +func (env *Environment) BlockResults(ctx context.Context, heightPtr *int64) (*coretypes.ResultBlockResults, error) { height, err := env.getHeight(env.BlockStore.Height(), heightPtr) if err != nil { return nil, err @@ -226,7 +226,7 @@ func (env *Environment) BlockResults(ctx *rpctypes.Context, heightPtr *int64) (* // BlockSearch searches for a paginated set of blocks matching BeginBlock and // EndBlock event search criteria. func (env *Environment) BlockSearch( - ctx *rpctypes.Context, + ctx context.Context, query string, pagePtr, perPagePtr *int, orderBy string, @@ -248,7 +248,7 @@ func (env *Environment) BlockSearch( } } - results, err := kvsink.SearchBlockEvents(ctx.Context(), q) + results, err := kvsink.SearchBlockEvents(ctx, q) if err != nil { return nil, err } diff --git a/internal/rpc/core/blocks_test.go b/internal/rpc/core/blocks_test.go index 213845bf4..b1746acb7 100644 --- a/internal/rpc/core/blocks_test.go +++ b/internal/rpc/core/blocks_test.go @@ -1,6 +1,7 @@ package core import ( + "context" "fmt" "testing" @@ -14,7 +15,6 @@ import ( "github.com/tendermint/tendermint/internal/state/mocks" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) func TestBlockchainInfo(t *testing.T) { @@ -108,8 +108,9 @@ func TestBlockResults(t *testing.T) { }}, } + ctx := context.Background() for _, tc := range testCases { - res, err := env.BlockResults(&rpctypes.Context{}, &tc.height) + res, err := env.BlockResults(ctx, &tc.height) if tc.wantErr { assert.Error(t, err) } else { diff --git a/internal/rpc/core/consensus.go b/internal/rpc/core/consensus.go index d17796fff..bc3a23ec8 100644 --- a/internal/rpc/core/consensus.go +++ b/internal/rpc/core/consensus.go @@ -1,9 +1,10 @@ package core import ( + "context" + tmmath "github.com/tendermint/tendermint/libs/math" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // Validators gets the validator set at the given block height. @@ -14,7 +15,7 @@ import ( // // More: https://docs.tendermint.com/master/rpc/#/Info/validators func (env *Environment) Validators( - ctx *rpctypes.Context, + ctx context.Context, heightPtr *int64, pagePtr, perPagePtr *int) (*coretypes.ResultValidators, error) { @@ -50,7 +51,7 @@ func (env *Environment) Validators( // DumpConsensusState dumps consensus state. // UNSTABLE // More: https://docs.tendermint.com/master/rpc/#/Info/dump_consensus_state -func (env *Environment) DumpConsensusState(ctx *rpctypes.Context) (*coretypes.ResultDumpConsensusState, error) { +func (env *Environment) DumpConsensusState(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) { // Get Peer consensus states. var peerStates []coretypes.PeerStateInfo @@ -91,7 +92,7 @@ func (env *Environment) DumpConsensusState(ctx *rpctypes.Context) (*coretypes.Re // ConsensusState returns a concise summary of the consensus state. // UNSTABLE // More: https://docs.tendermint.com/master/rpc/#/Info/consensus_state -func (env *Environment) GetConsensusState(ctx *rpctypes.Context) (*coretypes.ResultConsensusState, error) { +func (env *Environment) GetConsensusState(ctx context.Context) (*coretypes.ResultConsensusState, error) { // Get self round state. bz, err := env.ConsensusState.GetRoundStateSimpleJSON() return &coretypes.ResultConsensusState{RoundState: bz}, err @@ -101,7 +102,7 @@ func (env *Environment) GetConsensusState(ctx *rpctypes.Context) (*coretypes.Res // If no height is provided, it will fetch the latest consensus params. // More: https://docs.tendermint.com/master/rpc/#/Info/consensus_params func (env *Environment) ConsensusParams( - ctx *rpctypes.Context, + ctx context.Context, heightPtr *int64) (*coretypes.ResultConsensusParams, error) { // The latest consensus params that we know is the consensus params after the diff --git a/internal/rpc/core/dev.go b/internal/rpc/core/dev.go index 21c5154ff..702413ab8 100644 --- a/internal/rpc/core/dev.go +++ b/internal/rpc/core/dev.go @@ -1,12 +1,13 @@ package core import ( + "context" + "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // UnsafeFlushMempool removes all transactions from the mempool. -func (env *Environment) UnsafeFlushMempool(ctx *rpctypes.Context) (*coretypes.ResultUnsafeFlushMempool, error) { +func (env *Environment) UnsafeFlushMempool(ctx context.Context) (*coretypes.ResultUnsafeFlushMempool, error) { env.Mempool.Flush() return &coretypes.ResultUnsafeFlushMempool{}, nil } diff --git a/internal/rpc/core/events.go b/internal/rpc/core/events.go index 965291cdb..82235ae50 100644 --- a/internal/rpc/core/events.go +++ b/internal/rpc/core/events.go @@ -23,8 +23,9 @@ const ( // Subscribe for events via WebSocket. // More: https://docs.tendermint.com/master/rpc/#/Websocket/subscribe -func (env *Environment) Subscribe(ctx *rpctypes.Context, query string) (*coretypes.ResultSubscribe, error) { - addr := ctx.RemoteAddr() +func (env *Environment) Subscribe(ctx context.Context, query string) (*coretypes.ResultSubscribe, error) { + callInfo := rpctypes.GetCallInfo(ctx) + addr := callInfo.RemoteAddr() if env.EventBus.NumClients() >= env.Config.MaxSubscriptionClients { return nil, fmt.Errorf("max_subscription_clients %d reached", env.Config.MaxSubscriptionClients) @@ -41,7 +42,7 @@ func (env *Environment) Subscribe(ctx *rpctypes.Context, query string) (*coretyp return nil, fmt.Errorf("failed to parse query: %w", err) } - subCtx, cancel := context.WithTimeout(ctx.Context(), SubscribeTimeout) + subCtx, cancel := context.WithTimeout(ctx, SubscribeTimeout) defer cancel() sub, err := env.EventBus.SubscribeWithArgs(subCtx, tmpubsub.SubscribeArgs{ @@ -54,7 +55,7 @@ func (env *Environment) Subscribe(ctx *rpctypes.Context, query string) (*coretyp } // Capture the current ID, since it can change in the future. - subscriptionID := ctx.JSONReq.ID + subscriptionID := callInfo.RPCRequest.ID go func() { opctx, opcancel := context.WithCancel(context.Background()) defer opcancel() @@ -67,7 +68,7 @@ func (env *Environment) Subscribe(ctx *rpctypes.Context, query string) (*coretyp } else if errors.Is(err, tmpubsub.ErrTerminated) { // The subscription was terminated by the publisher. resp := rpctypes.RPCServerError(subscriptionID, err) - ok := ctx.WSConn.TryWriteRPCResponse(opctx, resp) + ok := callInfo.WSConn.TryWriteRPCResponse(opctx, resp) if !ok { env.Logger.Info("Unable to write response (slow client)", "to", addr, "subscriptionID", subscriptionID, "err", err) @@ -82,7 +83,7 @@ func (env *Environment) Subscribe(ctx *rpctypes.Context, query string) (*coretyp Events: msg.Events(), }) wctx, cancel := context.WithTimeout(opctx, 10*time.Second) - err = ctx.WSConn.WriteRPCResponse(wctx, resp) + err = callInfo.WSConn.WriteRPCResponse(wctx, resp) cancel() if err != nil { env.Logger.Info("Unable to write response (slow client)", @@ -96,8 +97,8 @@ func (env *Environment) Subscribe(ctx *rpctypes.Context, query string) (*coretyp // Unsubscribe from events via WebSocket. // More: https://docs.tendermint.com/master/rpc/#/Websocket/unsubscribe -func (env *Environment) Unsubscribe(ctx *rpctypes.Context, query string) (*coretypes.ResultUnsubscribe, error) { - args := tmpubsub.UnsubscribeArgs{Subscriber: ctx.RemoteAddr()} +func (env *Environment) Unsubscribe(ctx context.Context, query string) (*coretypes.ResultUnsubscribe, error) { + args := tmpubsub.UnsubscribeArgs{Subscriber: rpctypes.GetCallInfo(ctx).RemoteAddr()} env.Logger.Info("Unsubscribe from query", "remote", args.Subscriber, "subscription", query) var err error @@ -107,7 +108,7 @@ func (env *Environment) Unsubscribe(ctx *rpctypes.Context, query string) (*coret args.ID = query } - err = env.EventBus.Unsubscribe(ctx.Context(), args) + err = env.EventBus.Unsubscribe(ctx, args) if err != nil { return nil, err } @@ -116,10 +117,10 @@ func (env *Environment) Unsubscribe(ctx *rpctypes.Context, query string) (*coret // UnsubscribeAll from all events via WebSocket. // More: https://docs.tendermint.com/master/rpc/#/Websocket/unsubscribe_all -func (env *Environment) UnsubscribeAll(ctx *rpctypes.Context) (*coretypes.ResultUnsubscribe, error) { - addr := ctx.RemoteAddr() +func (env *Environment) UnsubscribeAll(ctx context.Context) (*coretypes.ResultUnsubscribe, error) { + addr := rpctypes.GetCallInfo(ctx).RemoteAddr() env.Logger.Info("Unsubscribe from all", "remote", addr) - err := env.EventBus.UnsubscribeAll(ctx.Context(), addr) + err := env.EventBus.UnsubscribeAll(ctx, addr) if err != nil { return nil, err } diff --git a/internal/rpc/core/evidence.go b/internal/rpc/core/evidence.go index a7641b99d..f85892d99 100644 --- a/internal/rpc/core/evidence.go +++ b/internal/rpc/core/evidence.go @@ -1,17 +1,17 @@ package core import ( + "context" "fmt" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) // BroadcastEvidence broadcasts evidence of the misbehavior. // More: https://docs.tendermint.com/master/rpc/#/Evidence/broadcast_evidence func (env *Environment) BroadcastEvidence( - ctx *rpctypes.Context, + ctx context.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) { if ev == nil { diff --git a/internal/rpc/core/health.go b/internal/rpc/core/health.go index fc355c7e7..c55aa58dc 100644 --- a/internal/rpc/core/health.go +++ b/internal/rpc/core/health.go @@ -1,13 +1,14 @@ package core import ( + "context" + "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // Health gets node health. Returns empty result (200 OK) on success, no // response - in case of an error. // More: https://docs.tendermint.com/master/rpc/#/Info/health -func (env *Environment) Health(ctx *rpctypes.Context) (*coretypes.ResultHealth, error) { +func (env *Environment) Health(ctx context.Context) (*coretypes.ResultHealth, error) { return &coretypes.ResultHealth{}, nil } diff --git a/internal/rpc/core/mempool.go b/internal/rpc/core/mempool.go index 6c145d3ad..751c7ee73 100644 --- a/internal/rpc/core/mempool.go +++ b/internal/rpc/core/mempool.go @@ -1,6 +1,7 @@ package core import ( + "context" "errors" "fmt" "math/rand" @@ -10,7 +11,6 @@ import ( "github.com/tendermint/tendermint/internal/mempool" "github.com/tendermint/tendermint/internal/state/indexer" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) @@ -20,8 +20,8 @@ import ( // BroadcastTxAsync returns right away, with no response. Does not wait for // CheckTx nor DeliverTx results. // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_async -func (env *Environment) BroadcastTxAsync(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - err := env.Mempool.CheckTx(ctx.Context(), tx, nil, mempool.TxInfo{}) +func (env *Environment) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { + err := env.Mempool.CheckTx(ctx, tx, nil, mempool.TxInfo{}) if err != nil { return nil, err } @@ -32,10 +32,10 @@ func (env *Environment) BroadcastTxAsync(ctx *rpctypes.Context, tx types.Tx) (*c // BroadcastTxSync returns with the response from CheckTx. Does not wait for // DeliverTx result. // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_sync -func (env *Environment) BroadcastTxSync(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { +func (env *Environment) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { resCh := make(chan *abci.Response, 1) err := env.Mempool.CheckTx( - ctx.Context(), + ctx, tx, func(res *abci.Response) { resCh <- res }, mempool.TxInfo{}, @@ -59,10 +59,10 @@ func (env *Environment) BroadcastTxSync(ctx *rpctypes.Context, tx types.Tx) (*co // BroadcastTxCommit returns with the responses from CheckTx and DeliverTx. // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_commit -func (env *Environment) BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { +func (env *Environment) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { resCh := make(chan *abci.Response, 1) err := env.Mempool.CheckTx( - ctx.Context(), + ctx, tx, func(res *abci.Response) { resCh <- res }, mempool.TxInfo{}, @@ -89,7 +89,7 @@ func (env *Environment) BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (* for { count++ select { - case <-ctx.Context().Done(): + case <-ctx.Done(): env.Logger.Error("error on broadcastTxCommit", "duration", time.Since(startAt), "err", err) @@ -120,7 +120,7 @@ func (env *Environment) BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (* // UnconfirmedTxs gets unconfirmed transactions (maximum ?limit entries) // including their number. // More: https://docs.tendermint.com/master/rpc/#/Info/unconfirmed_txs -func (env *Environment) UnconfirmedTxs(ctx *rpctypes.Context, limitPtr *int) (*coretypes.ResultUnconfirmedTxs, error) { +func (env *Environment) UnconfirmedTxs(ctx context.Context, limitPtr *int) (*coretypes.ResultUnconfirmedTxs, error) { // reuse per_page validator limit := env.validatePerPage(limitPtr) @@ -134,7 +134,7 @@ func (env *Environment) UnconfirmedTxs(ctx *rpctypes.Context, limitPtr *int) (*c // NumUnconfirmedTxs gets number of unconfirmed transactions. // More: https://docs.tendermint.com/master/rpc/#/Info/num_unconfirmed_txs -func (env *Environment) NumUnconfirmedTxs(ctx *rpctypes.Context) (*coretypes.ResultUnconfirmedTxs, error) { +func (env *Environment) NumUnconfirmedTxs(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) { return &coretypes.ResultUnconfirmedTxs{ Count: env.Mempool.Size(), Total: env.Mempool.Size(), @@ -144,14 +144,14 @@ func (env *Environment) NumUnconfirmedTxs(ctx *rpctypes.Context) (*coretypes.Res // CheckTx checks the transaction without executing it. The transaction won't // be added to the mempool either. // More: https://docs.tendermint.com/master/rpc/#/Tx/check_tx -func (env *Environment) CheckTx(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultCheckTx, error) { - res, err := env.ProxyAppMempool.CheckTxSync(ctx.Context(), abci.RequestCheckTx{Tx: tx}) +func (env *Environment) CheckTx(ctx context.Context, tx types.Tx) (*coretypes.ResultCheckTx, error) { + res, err := env.ProxyAppMempool.CheckTxSync(ctx, abci.RequestCheckTx{Tx: tx}) if err != nil { return nil, err } return &coretypes.ResultCheckTx{ResponseCheckTx: *res}, nil } -func (env *Environment) RemoveTx(ctx *rpctypes.Context, txkey types.TxKey) error { +func (env *Environment) RemoveTx(ctx context.Context, txkey types.TxKey) error { return env.Mempool.RemoveTxByKey(txkey) } diff --git a/internal/rpc/core/net.go b/internal/rpc/core/net.go index fdf4be69b..3cead393c 100644 --- a/internal/rpc/core/net.go +++ b/internal/rpc/core/net.go @@ -1,16 +1,16 @@ package core import ( + "context" "errors" "fmt" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // NetInfo returns network info. // More: https://docs.tendermint.com/master/rpc/#/Info/net_info -func (env *Environment) NetInfo(ctx *rpctypes.Context) (*coretypes.ResultNetInfo, error) { +func (env *Environment) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, error) { peerList := env.PeerManager.Peers() peers := make([]coretypes.Peer, 0, len(peerList)) @@ -36,7 +36,7 @@ func (env *Environment) NetInfo(ctx *rpctypes.Context) (*coretypes.ResultNetInfo // Genesis returns genesis file. // More: https://docs.tendermint.com/master/rpc/#/Info/genesis -func (env *Environment) Genesis(ctx *rpctypes.Context) (*coretypes.ResultGenesis, error) { +func (env *Environment) Genesis(ctx context.Context) (*coretypes.ResultGenesis, error) { if len(env.genChunks) > 1 { return nil, errors.New("genesis response is large, please use the genesis_chunked API instead") } @@ -44,7 +44,7 @@ func (env *Environment) Genesis(ctx *rpctypes.Context) (*coretypes.ResultGenesis return &coretypes.ResultGenesis{Genesis: env.GenDoc}, nil } -func (env *Environment) GenesisChunked(ctx *rpctypes.Context, chunk uint) (*coretypes.ResultGenesisChunk, error) { +func (env *Environment) GenesisChunked(ctx context.Context, chunk uint) (*coretypes.ResultGenesisChunk, error) { if env.genChunks == nil { return nil, fmt.Errorf("service configuration error, genesis chunks are not initialized") } diff --git a/internal/rpc/core/status.go b/internal/rpc/core/status.go index b883c6dc2..44a2b7469 100644 --- a/internal/rpc/core/status.go +++ b/internal/rpc/core/status.go @@ -2,18 +2,18 @@ package core import ( "bytes" + "context" "time" tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) // Status returns Tendermint status including node info, pubkey, latest block // hash, app hash, block height, current max peer block height, and time. // More: https://docs.tendermint.com/master/rpc/#/Info/status -func (env *Environment) Status(ctx *rpctypes.Context) (*coretypes.ResultStatus, error) { +func (env *Environment) Status(ctx context.Context) (*coretypes.ResultStatus, error) { var ( earliestBlockHeight int64 earliestBlockHash tmbytes.HexBytes diff --git a/internal/rpc/core/tx.go b/internal/rpc/core/tx.go index 98fedc10a..126875d0d 100644 --- a/internal/rpc/core/tx.go +++ b/internal/rpc/core/tx.go @@ -1,6 +1,7 @@ package core import ( + "context" "errors" "fmt" "sort" @@ -10,7 +11,6 @@ import ( "github.com/tendermint/tendermint/libs/bytes" tmmath "github.com/tendermint/tendermint/libs/math" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) @@ -18,7 +18,7 @@ import ( // transaction is in the mempool, invalidated, or was not sent in the first // place. // More: https://docs.tendermint.com/master/rpc/#/Info/tx -func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { +func (env *Environment) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { // if index is disabled, return error // N.B. The hash parameter is HexBytes so that the reflective parameter @@ -63,7 +63,7 @@ func (env *Environment) Tx(ctx *rpctypes.Context, hash bytes.HexBytes, prove boo // list of transactions (maximum ?per_page entries) and the total count. // More: https://docs.tendermint.com/master/rpc/#/Info/tx_search func (env *Environment) TxSearch( - ctx *rpctypes.Context, + ctx context.Context, query string, prove bool, pagePtr, perPagePtr *int, @@ -83,7 +83,7 @@ func (env *Environment) TxSearch( for _, sink := range env.EventSinks { if sink.Type() == indexer.KV { - results, err := sink.SearchTxEvents(ctx.Context(), q) + results, err := sink.SearchTxEvents(ctx, q) if err != nil { return nil, err } diff --git a/light/proxy/routes.go b/light/proxy/routes.go index ac2e8b5df..4fb815b7e 100644 --- a/light/proxy/routes.go +++ b/light/proxy/routes.go @@ -1,12 +1,13 @@ package proxy import ( + "context" + "github.com/tendermint/tendermint/libs/bytes" lrpc "github.com/tendermint/tendermint/light/rpc" rpcclient "github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/coretypes" rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) @@ -54,113 +55,113 @@ func RPCRoutes(c *lrpc.Client) map[string]*rpcserver.RPCFunc { } } -type rpcHealthFunc func(ctx *rpctypes.Context) (*coretypes.ResultHealth, error) +type rpcHealthFunc func(ctx context.Context) (*coretypes.ResultHealth, error) func makeHealthFunc(c *lrpc.Client) rpcHealthFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultHealth, error) { - return c.Health(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultHealth, error) { + return c.Health(ctx) } } -type rpcStatusFunc func(ctx *rpctypes.Context) (*coretypes.ResultStatus, error) +type rpcStatusFunc func(ctx context.Context) (*coretypes.ResultStatus, error) // nolint: interfacer func makeStatusFunc(c *lrpc.Client) rpcStatusFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultStatus, error) { - return c.Status(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultStatus, error) { + return c.Status(ctx) } } -type rpcNetInfoFunc func(ctx *rpctypes.Context) (*coretypes.ResultNetInfo, error) +type rpcNetInfoFunc func(ctx context.Context) (*coretypes.ResultNetInfo, error) func makeNetInfoFunc(c *lrpc.Client) rpcNetInfoFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultNetInfo, error) { - return c.NetInfo(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultNetInfo, error) { + return c.NetInfo(ctx) } } -type rpcBlockchainInfoFunc func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) +type rpcBlockchainInfoFunc func(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) func makeBlockchainInfoFunc(c *lrpc.Client) rpcBlockchainInfoFunc { - return func(ctx *rpctypes.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) { - return c.BlockchainInfo(ctx.Context(), minHeight, maxHeight) + return func(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) { + return c.BlockchainInfo(ctx, minHeight, maxHeight) } } -type rpcGenesisFunc func(ctx *rpctypes.Context) (*coretypes.ResultGenesis, error) +type rpcGenesisFunc func(ctx context.Context) (*coretypes.ResultGenesis, error) func makeGenesisFunc(c *lrpc.Client) rpcGenesisFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultGenesis, error) { - return c.Genesis(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultGenesis, error) { + return c.Genesis(ctx) } } -type rpcGenesisChunkedFunc func(ctx *rpctypes.Context, chunk uint) (*coretypes.ResultGenesisChunk, error) +type rpcGenesisChunkedFunc func(ctx context.Context, chunk uint) (*coretypes.ResultGenesisChunk, error) func makeGenesisChunkedFunc(c *lrpc.Client) rpcGenesisChunkedFunc { - return func(ctx *rpctypes.Context, chunk uint) (*coretypes.ResultGenesisChunk, error) { - return c.GenesisChunked(ctx.Context(), chunk) + return func(ctx context.Context, chunk uint) (*coretypes.ResultGenesisChunk, error) { + return c.GenesisChunked(ctx, chunk) } } -type rpcHeaderFunc func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultHeader, error) +type rpcHeaderFunc func(ctx context.Context, height *int64) (*coretypes.ResultHeader, error) func makeHeaderFunc(c *lrpc.Client) rpcHeaderFunc { - return func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultHeader, error) { - return c.Header(ctx.Context(), height) + return func(ctx context.Context, height *int64) (*coretypes.ResultHeader, error) { + return c.Header(ctx, height) } } -type rpcHeaderByHashFunc func(ctx *rpctypes.Context, hash []byte) (*coretypes.ResultHeader, error) +type rpcHeaderByHashFunc func(ctx context.Context, hash []byte) (*coretypes.ResultHeader, error) func makeHeaderByHashFunc(c *lrpc.Client) rpcHeaderByHashFunc { - return func(ctx *rpctypes.Context, hash []byte) (*coretypes.ResultHeader, error) { - return c.HeaderByHash(ctx.Context(), hash) + return func(ctx context.Context, hash []byte) (*coretypes.ResultHeader, error) { + return c.HeaderByHash(ctx, hash) } } -type rpcBlockFunc func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultBlock, error) +type rpcBlockFunc func(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) func makeBlockFunc(c *lrpc.Client) rpcBlockFunc { - return func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultBlock, error) { - return c.Block(ctx.Context(), height) + return func(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { + return c.Block(ctx, height) } } -type rpcBlockByHashFunc func(ctx *rpctypes.Context, hash []byte) (*coretypes.ResultBlock, error) +type rpcBlockByHashFunc func(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error) func makeBlockByHashFunc(c *lrpc.Client) rpcBlockByHashFunc { - return func(ctx *rpctypes.Context, hash []byte) (*coretypes.ResultBlock, error) { - return c.BlockByHash(ctx.Context(), hash) + return func(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error) { + return c.BlockByHash(ctx, hash) } } -type rpcBlockResultsFunc func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultBlockResults, error) +type rpcBlockResultsFunc func(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) func makeBlockResultsFunc(c *lrpc.Client) rpcBlockResultsFunc { - return func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultBlockResults, error) { - return c.BlockResults(ctx.Context(), height) + return func(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { + return c.BlockResults(ctx, height) } } -type rpcCommitFunc func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultCommit, error) +type rpcCommitFunc func(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) func makeCommitFunc(c *lrpc.Client) rpcCommitFunc { - return func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultCommit, error) { - return c.Commit(ctx.Context(), height) + return func(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { + return c.Commit(ctx, height) } } -type rpcTxFunc func(ctx *rpctypes.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) +type rpcTxFunc func(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) func makeTxFunc(c *lrpc.Client) rpcTxFunc { - return func(ctx *rpctypes.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { - return c.Tx(ctx.Context(), hash, prove) + return func(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error) { + return c.Tx(ctx, hash, prove) } } type rpcTxSearchFunc func( - ctx *rpctypes.Context, + ctx context.Context, query string, prove bool, page, perPage *int, @@ -169,18 +170,18 @@ type rpcTxSearchFunc func( func makeTxSearchFunc(c *lrpc.Client) rpcTxSearchFunc { return func( - ctx *rpctypes.Context, + ctx context.Context, query string, prove bool, page, perPage *int, orderBy string, ) (*coretypes.ResultTxSearch, error) { - return c.TxSearch(ctx.Context(), query, prove, page, perPage, orderBy) + return c.TxSearch(ctx, query, prove, page, perPage, orderBy) } } type rpcBlockSearchFunc func( - ctx *rpctypes.Context, + ctx context.Context, query string, prove bool, page, perPage *int, @@ -189,116 +190,116 @@ type rpcBlockSearchFunc func( func makeBlockSearchFunc(c *lrpc.Client) rpcBlockSearchFunc { return func( - ctx *rpctypes.Context, + ctx context.Context, query string, prove bool, page, perPage *int, orderBy string, ) (*coretypes.ResultBlockSearch, error) { - return c.BlockSearch(ctx.Context(), query, page, perPage, orderBy) + return c.BlockSearch(ctx, query, page, perPage, orderBy) } } -type rpcValidatorsFunc func(ctx *rpctypes.Context, height *int64, +type rpcValidatorsFunc func(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) func makeValidatorsFunc(c *lrpc.Client) rpcValidatorsFunc { - return func(ctx *rpctypes.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) { - return c.Validators(ctx.Context(), height, page, perPage) + return func(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) { + return c.Validators(ctx, height, page, perPage) } } -type rpcDumpConsensusStateFunc func(ctx *rpctypes.Context) (*coretypes.ResultDumpConsensusState, error) +type rpcDumpConsensusStateFunc func(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) func makeDumpConsensusStateFunc(c *lrpc.Client) rpcDumpConsensusStateFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultDumpConsensusState, error) { - return c.DumpConsensusState(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) { + return c.DumpConsensusState(ctx) } } -type rpcConsensusStateFunc func(ctx *rpctypes.Context) (*coretypes.ResultConsensusState, error) +type rpcConsensusStateFunc func(ctx context.Context) (*coretypes.ResultConsensusState, error) func makeConsensusStateFunc(c *lrpc.Client) rpcConsensusStateFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultConsensusState, error) { - return c.ConsensusState(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultConsensusState, error) { + return c.ConsensusState(ctx) } } -type rpcConsensusParamsFunc func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultConsensusParams, error) +type rpcConsensusParamsFunc func(ctx context.Context, height *int64) (*coretypes.ResultConsensusParams, error) func makeConsensusParamsFunc(c *lrpc.Client) rpcConsensusParamsFunc { - return func(ctx *rpctypes.Context, height *int64) (*coretypes.ResultConsensusParams, error) { - return c.ConsensusParams(ctx.Context(), height) + return func(ctx context.Context, height *int64) (*coretypes.ResultConsensusParams, error) { + return c.ConsensusParams(ctx, height) } } -type rpcUnconfirmedTxsFunc func(ctx *rpctypes.Context, limit *int) (*coretypes.ResultUnconfirmedTxs, error) +type rpcUnconfirmedTxsFunc func(ctx context.Context, limit *int) (*coretypes.ResultUnconfirmedTxs, error) func makeUnconfirmedTxsFunc(c *lrpc.Client) rpcUnconfirmedTxsFunc { - return func(ctx *rpctypes.Context, limit *int) (*coretypes.ResultUnconfirmedTxs, error) { - return c.UnconfirmedTxs(ctx.Context(), limit) + return func(ctx context.Context, limit *int) (*coretypes.ResultUnconfirmedTxs, error) { + return c.UnconfirmedTxs(ctx, limit) } } -type rpcNumUnconfirmedTxsFunc func(ctx *rpctypes.Context) (*coretypes.ResultUnconfirmedTxs, error) +type rpcNumUnconfirmedTxsFunc func(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) func makeNumUnconfirmedTxsFunc(c *lrpc.Client) rpcNumUnconfirmedTxsFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultUnconfirmedTxs, error) { - return c.NumUnconfirmedTxs(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) { + return c.NumUnconfirmedTxs(ctx) } } -type rpcBroadcastTxCommitFunc func(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) +type rpcBroadcastTxCommitFunc func(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) func makeBroadcastTxCommitFunc(c *lrpc.Client) rpcBroadcastTxCommitFunc { - return func(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { - return c.BroadcastTxCommit(ctx.Context(), tx) + return func(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { + return c.BroadcastTxCommit(ctx, tx) } } -type rpcBroadcastTxSyncFunc func(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) +type rpcBroadcastTxSyncFunc func(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) func makeBroadcastTxSyncFunc(c *lrpc.Client) rpcBroadcastTxSyncFunc { - return func(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - return c.BroadcastTxSync(ctx.Context(), tx) + return func(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { + return c.BroadcastTxSync(ctx, tx) } } -type rpcBroadcastTxAsyncFunc func(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) +type rpcBroadcastTxAsyncFunc func(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) func makeBroadcastTxAsyncFunc(c *lrpc.Client) rpcBroadcastTxAsyncFunc { - return func(ctx *rpctypes.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - return c.BroadcastTxAsync(ctx.Context(), tx) + return func(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { + return c.BroadcastTxAsync(ctx, tx) } } -type rpcABCIQueryFunc func(ctx *rpctypes.Context, path string, +type rpcABCIQueryFunc func(ctx context.Context, path string, data bytes.HexBytes, height int64, prove bool) (*coretypes.ResultABCIQuery, error) func makeABCIQueryFunc(c *lrpc.Client) rpcABCIQueryFunc { - return func(ctx *rpctypes.Context, path string, data bytes.HexBytes, + return func(ctx context.Context, path string, data bytes.HexBytes, height int64, prove bool) (*coretypes.ResultABCIQuery, error) { - return c.ABCIQueryWithOptions(ctx.Context(), path, data, rpcclient.ABCIQueryOptions{ + return c.ABCIQueryWithOptions(ctx, path, data, rpcclient.ABCIQueryOptions{ Height: height, Prove: prove, }) } } -type rpcABCIInfoFunc func(ctx *rpctypes.Context) (*coretypes.ResultABCIInfo, error) +type rpcABCIInfoFunc func(ctx context.Context) (*coretypes.ResultABCIInfo, error) func makeABCIInfoFunc(c *lrpc.Client) rpcABCIInfoFunc { - return func(ctx *rpctypes.Context) (*coretypes.ResultABCIInfo, error) { - return c.ABCIInfo(ctx.Context()) + return func(ctx context.Context) (*coretypes.ResultABCIInfo, error) { + return c.ABCIInfo(ctx) } } -type rpcBroadcastEvidenceFunc func(ctx *rpctypes.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) +type rpcBroadcastEvidenceFunc func(ctx context.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) // nolint: interfacer func makeBroadcastEvidenceFunc(c *lrpc.Client) rpcBroadcastEvidenceFunc { - return func(ctx *rpctypes.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) { - return c.BroadcastEvidence(ctx.Context(), ev) + return func(ctx context.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) { + return c.BroadcastEvidence(ctx, ev) } } diff --git a/light/rpc/client.go b/light/rpc/client.go index 08ef27a6d..41ed97401 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -615,11 +615,12 @@ func (c *Client) RegisterOpDecoder(typ string, dec merkle.OpDecoder) { // SubscribeWS subscribes for events using the given query and remote address as // a subscriber, but does not verify responses (UNSAFE)! // TODO: verify data -func (c *Client) SubscribeWS(ctx *rpctypes.Context, query string) (*coretypes.ResultSubscribe, error) { +func (c *Client) SubscribeWS(ctx context.Context, query string) (*coretypes.ResultSubscribe, error) { bctx, bcancel := context.WithCancel(context.Background()) c.closers = append(c.closers, bcancel) - out, err := c.next.Subscribe(bctx, ctx.RemoteAddr(), query) + callInfo := rpctypes.GetCallInfo(ctx) + out, err := c.next.Subscribe(bctx, callInfo.RemoteAddr(), query) if err != nil { return nil, err } @@ -630,9 +631,9 @@ func (c *Client) SubscribeWS(ctx *rpctypes.Context, query string) (*coretypes.Re case resultEvent := <-out: // We should have a switch here that performs a validation // depending on the event's type. - ctx.WSConn.TryWriteRPCResponse(bctx, + callInfo.WSConn.TryWriteRPCResponse(bctx, rpctypes.NewRPCSuccessResponse( - rpctypes.JSONRPCStringID(fmt.Sprintf("%v#event", ctx.JSONReq.ID)), + rpctypes.JSONRPCStringID(fmt.Sprintf("%v#event", callInfo.RPCRequest.ID)), resultEvent, )) case <-bctx.Done(): @@ -646,8 +647,8 @@ func (c *Client) SubscribeWS(ctx *rpctypes.Context, query string) (*coretypes.Re // UnsubscribeWS calls original client's Unsubscribe using remote address as a // subscriber. -func (c *Client) UnsubscribeWS(ctx *rpctypes.Context, query string) (*coretypes.ResultUnsubscribe, error) { - err := c.next.Unsubscribe(context.Background(), ctx.RemoteAddr(), query) +func (c *Client) UnsubscribeWS(ctx context.Context, query string) (*coretypes.ResultUnsubscribe, error) { + err := c.next.Unsubscribe(context.Background(), rpctypes.GetCallInfo(ctx).RemoteAddr(), query) if err != nil { return nil, err } @@ -656,8 +657,8 @@ func (c *Client) UnsubscribeWS(ctx *rpctypes.Context, query string) (*coretypes. // UnsubscribeAllWS calls original client's UnsubscribeAll using remote address // as a subscriber. -func (c *Client) UnsubscribeAllWS(ctx *rpctypes.Context) (*coretypes.ResultUnsubscribe, error) { - err := c.next.UnsubscribeAll(context.Background(), ctx.RemoteAddr()) +func (c *Client) UnsubscribeAllWS(ctx context.Context) (*coretypes.ResultUnsubscribe, error) { + err := c.next.UnsubscribeAll(context.Background(), rpctypes.GetCallInfo(ctx).RemoteAddr()) if err != nil { return nil, err } diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index 4a833af9c..69cbb3ebd 100644 --- a/rpc/client/local/local.go +++ b/rpc/client/local/local.go @@ -14,7 +14,6 @@ import ( "github.com/tendermint/tendermint/libs/log" rpcclient "github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) @@ -41,7 +40,6 @@ backoff (10ms -> 20ms -> 40ms) until successful. type Local struct { *eventbus.EventBus Logger log.Logger - ctx *rpctypes.Context env *rpccore.Environment } @@ -61,7 +59,6 @@ func New(node NodeService) (*Local, error) { return &Local{ EventBus: node.EventBus(), Logger: log.NewNopLogger(), - ctx: &rpctypes.Context{}, env: env, }, nil } @@ -74,11 +71,11 @@ func (c *Local) SetLogger(l log.Logger) { } func (c *Local) Status(ctx context.Context) (*coretypes.ResultStatus, error) { - return c.env.Status(c.ctx) + return c.env.Status(ctx) } func (c *Local) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { - return c.env.ABCIInfo(c.ctx) + return c.env.ABCIInfo(ctx) } func (c *Local) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*coretypes.ResultABCIQuery, error) { @@ -90,31 +87,31 @@ func (c *Local) ABCIQueryWithOptions( path string, data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { - return c.env.ABCIQuery(c.ctx, path, data, opts.Height, opts.Prove) + return c.env.ABCIQuery(ctx, path, data, opts.Height, opts.Prove) } func (c *Local) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { - return c.env.BroadcastTxCommit(c.ctx, tx) + return c.env.BroadcastTxCommit(ctx, tx) } func (c *Local) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - return c.env.BroadcastTxAsync(c.ctx, tx) + return c.env.BroadcastTxAsync(ctx, tx) } func (c *Local) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - return c.env.BroadcastTxSync(c.ctx, tx) + return c.env.BroadcastTxSync(ctx, tx) } func (c *Local) UnconfirmedTxs(ctx context.Context, limit *int) (*coretypes.ResultUnconfirmedTxs, error) { - return c.env.UnconfirmedTxs(c.ctx, limit) + return c.env.UnconfirmedTxs(ctx, limit) } func (c *Local) NumUnconfirmedTxs(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) { - return c.env.NumUnconfirmedTxs(c.ctx) + return c.env.NumUnconfirmedTxs(ctx) } func (c *Local) CheckTx(ctx context.Context, tx types.Tx) (*coretypes.ResultCheckTx, error) { - return c.env.CheckTx(c.ctx, tx) + return c.env.CheckTx(ctx, tx) } func (c *Local) RemoveTx(ctx context.Context, txKey types.TxKey) error { @@ -122,91 +119,91 @@ func (c *Local) RemoveTx(ctx context.Context, txKey types.TxKey) error { } func (c *Local) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, error) { - return c.env.NetInfo(c.ctx) + return c.env.NetInfo(ctx) } func (c *Local) DumpConsensusState(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) { - return c.env.DumpConsensusState(c.ctx) + return c.env.DumpConsensusState(ctx) } func (c *Local) ConsensusState(ctx context.Context) (*coretypes.ResultConsensusState, error) { - return c.env.GetConsensusState(c.ctx) + return c.env.GetConsensusState(ctx) } func (c *Local) ConsensusParams(ctx context.Context, height *int64) (*coretypes.ResultConsensusParams, error) { - return c.env.ConsensusParams(c.ctx, height) + return c.env.ConsensusParams(ctx, height) } func (c *Local) Health(ctx context.Context) (*coretypes.ResultHealth, error) { - return c.env.Health(c.ctx) + return c.env.Health(ctx) } func (c *Local) BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) { - return c.env.BlockchainInfo(c.ctx, minHeight, maxHeight) + return c.env.BlockchainInfo(ctx, minHeight, maxHeight) } func (c *Local) Genesis(ctx context.Context) (*coretypes.ResultGenesis, error) { - return c.env.Genesis(c.ctx) + return c.env.Genesis(ctx) } func (c *Local) GenesisChunked(ctx context.Context, id uint) (*coretypes.ResultGenesisChunk, error) { - return c.env.GenesisChunked(c.ctx, id) + return c.env.GenesisChunked(ctx, id) } func (c *Local) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { - return c.env.Block(c.ctx, height) + return c.env.Block(ctx, height) } func (c *Local) BlockByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { - return c.env.BlockByHash(c.ctx, hash) + return c.env.BlockByHash(ctx, hash) } func (c *Local) BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error) { - return c.env.BlockResults(c.ctx, height) + return c.env.BlockResults(ctx, height) } func (c *Local) Header(ctx context.Context, height *int64) (*coretypes.ResultHeader, error) { - return c.env.Header(c.ctx, height) + return c.env.Header(ctx, height) } func (c *Local) HeaderByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) { - return c.env.HeaderByHash(c.ctx, hash) + return c.env.HeaderByHash(ctx, hash) } func (c *Local) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { - return c.env.Commit(c.ctx, height) + return c.env.Commit(ctx, height) } func (c *Local) Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) { - return c.env.Validators(c.ctx, height, page, perPage) + return c.env.Validators(ctx, height, page, perPage) } func (c *Local) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) { - return c.env.Tx(c.ctx, hash, prove) + return c.env.Tx(ctx, hash, prove) } func (c *Local) TxSearch( - _ context.Context, + ctx context.Context, queryString string, prove bool, page, perPage *int, orderBy string, ) (*coretypes.ResultTxSearch, error) { - return c.env.TxSearch(c.ctx, queryString, prove, page, perPage, orderBy) + return c.env.TxSearch(ctx, queryString, prove, page, perPage, orderBy) } func (c *Local) BlockSearch( - _ context.Context, + ctx context.Context, queryString string, page, perPage *int, orderBy string, ) (*coretypes.ResultBlockSearch, error) { - return c.env.BlockSearch(c.ctx, queryString, page, perPage, orderBy) + return c.env.BlockSearch(ctx, queryString, page, perPage, orderBy) } func (c *Local) BroadcastEvidence(ctx context.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) { - return c.env.BroadcastEvidence(c.ctx, ev) + return c.env.BroadcastEvidence(ctx, ev) } func (c *Local) Subscribe( diff --git a/rpc/client/mock/client.go b/rpc/client/mock/client.go index b57e661cb..05a3ca9cb 100644 --- a/rpc/client/mock/client.go +++ b/rpc/client/mock/client.go @@ -22,7 +22,6 @@ import ( "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/coretypes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" "github.com/tendermint/tendermint/types" ) @@ -76,11 +75,11 @@ func (c Call) GetResponse(args interface{}) (interface{}, error) { } func (c Client) Status(ctx context.Context) (*coretypes.ResultStatus, error) { - return c.env.Status(&rpctypes.Context{}) + return c.env.Status(ctx) } func (c Client) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) { - return c.env.ABCIInfo(&rpctypes.Context{}) + return c.env.ABCIInfo(ctx) } func (c Client) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*coretypes.ResultABCIQuery, error) { @@ -92,69 +91,69 @@ func (c Client) ABCIQueryWithOptions( path string, data bytes.HexBytes, opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { - return c.env.ABCIQuery(&rpctypes.Context{}, path, data, opts.Height, opts.Prove) + return c.env.ABCIQuery(ctx, path, data, opts.Height, opts.Prove) } func (c Client) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) { - return c.env.BroadcastTxCommit(&rpctypes.Context{}, tx) + return c.env.BroadcastTxCommit(ctx, tx) } func (c Client) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - return c.env.BroadcastTxAsync(&rpctypes.Context{}, tx) + return c.env.BroadcastTxAsync(ctx, tx) } func (c Client) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) { - return c.env.BroadcastTxSync(&rpctypes.Context{}, tx) + return c.env.BroadcastTxSync(ctx, tx) } func (c Client) CheckTx(ctx context.Context, tx types.Tx) (*coretypes.ResultCheckTx, error) { - return c.env.CheckTx(&rpctypes.Context{}, tx) + return c.env.CheckTx(ctx, tx) } func (c Client) NetInfo(ctx context.Context) (*coretypes.ResultNetInfo, error) { - return c.env.NetInfo(&rpctypes.Context{}) + return c.env.NetInfo(ctx) } func (c Client) ConsensusState(ctx context.Context) (*coretypes.ResultConsensusState, error) { - return c.env.GetConsensusState(&rpctypes.Context{}) + return c.env.GetConsensusState(ctx) } func (c Client) DumpConsensusState(ctx context.Context) (*coretypes.ResultDumpConsensusState, error) { - return c.env.DumpConsensusState(&rpctypes.Context{}) + return c.env.DumpConsensusState(ctx) } func (c Client) ConsensusParams(ctx context.Context, height *int64) (*coretypes.ResultConsensusParams, error) { - return c.env.ConsensusParams(&rpctypes.Context{}, height) + return c.env.ConsensusParams(ctx, height) } func (c Client) Health(ctx context.Context) (*coretypes.ResultHealth, error) { - return c.env.Health(&rpctypes.Context{}) + return c.env.Health(ctx) } func (c Client) BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) { - return c.env.BlockchainInfo(&rpctypes.Context{}, minHeight, maxHeight) + return c.env.BlockchainInfo(ctx, minHeight, maxHeight) } func (c Client) Genesis(ctx context.Context) (*coretypes.ResultGenesis, error) { - return c.env.Genesis(&rpctypes.Context{}) + return c.env.Genesis(ctx) } func (c Client) Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) { - return c.env.Block(&rpctypes.Context{}, height) + return c.env.Block(ctx, height) } func (c Client) BlockByHash(ctx context.Context, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { - return c.env.BlockByHash(&rpctypes.Context{}, hash) + return c.env.BlockByHash(ctx, hash) } func (c Client) Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error) { - return c.env.Commit(&rpctypes.Context{}, height) + return c.env.Commit(ctx, height) } func (c Client) Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) { - return c.env.Validators(&rpctypes.Context{}, height, page, perPage) + return c.env.Validators(ctx, height, page, perPage) } func (c Client) BroadcastEvidence(ctx context.Context, ev types.Evidence) (*coretypes.ResultBroadcastEvidence, error) { - return c.env.BroadcastEvidence(&rpctypes.Context{}, ev) + return c.env.BroadcastEvidence(ctx, ev) } diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index 2c353e508..3ad0599ed 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -21,7 +21,6 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/rpc/jsonrpc/client" "github.com/tendermint/tendermint/rpc/jsonrpc/server" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) // Client and Server should work over tcp or unix sockets @@ -61,23 +60,23 @@ var Routes = map[string]*server.RPCFunc{ "echo_int": server.NewRPCFunc(EchoIntResult, "arg", false), } -func EchoResult(ctx *rpctypes.Context, v string) (*ResultEcho, error) { +func EchoResult(ctx context.Context, v string) (*ResultEcho, error) { return &ResultEcho{v}, nil } -func EchoWSResult(ctx *rpctypes.Context, v string) (*ResultEcho, error) { +func EchoWSResult(ctx context.Context, v string) (*ResultEcho, error) { return &ResultEcho{v}, nil } -func EchoIntResult(ctx *rpctypes.Context, v int) (*ResultEchoInt, error) { +func EchoIntResult(ctx context.Context, v int) (*ResultEchoInt, error) { return &ResultEchoInt{v}, nil } -func EchoBytesResult(ctx *rpctypes.Context, v []byte) (*ResultEchoBytes, error) { +func EchoBytesResult(ctx context.Context, v []byte) (*ResultEchoBytes, error) { return &ResultEchoBytes{v}, nil } -func EchoDataBytesResult(ctx *rpctypes.Context, v tmbytes.HexBytes) (*ResultEchoDataBytes, error) { +func EchoDataBytesResult(ctx context.Context, v tmbytes.HexBytes) (*ResultEchoDataBytes, error) { return &ResultEchoDataBytes{v}, nil } diff --git a/rpc/jsonrpc/server/http_json_handler.go b/rpc/jsonrpc/server/http_json_handler.go index 879a58df9..6111aa084 100644 --- a/rpc/jsonrpc/server/http_json_handler.go +++ b/rpc/jsonrpc/server/http_json_handler.go @@ -206,10 +206,11 @@ func arrayParamsToArgs( // parseParams parses the JSON parameters of rpcReq into the arguments of fn, // returning the corresponding argument values or an error. func parseParams(fn *RPCFunc, httpReq *http.Request, rpcReq rpctypes.RPCRequest) ([]reflect.Value, error) { - args := []reflect.Value{reflect.ValueOf(&rpctypes.Context{ - JSONReq: &rpcReq, - HTTPReq: httpReq, - })} + ctx := rpctypes.WithCallInfo(httpReq.Context(), &rpctypes.CallInfo{ + RPCRequest: &rpcReq, + HTTPRequest: httpReq, + }) + args := []reflect.Value{reflect.ValueOf(ctx)} if len(rpcReq.Params) == 0 { return args, nil } @@ -224,7 +225,7 @@ func parseParams(fn *RPCFunc, httpReq *http.Request, rpcReq rpctypes.RPCRequest) // array. // // Example: -// rpcFunc.args = [rpctypes.Context string] +// rpcFunc.args = [context.Context string] // rpcFunc.argNames = ["arg"] func jsonParamsToArgs(rpcFunc *RPCFunc, raw []byte) ([]reflect.Value, error) { const argsOffset = 1 diff --git a/rpc/jsonrpc/server/http_json_handler_test.go b/rpc/jsonrpc/server/http_json_handler_test.go index 1a65d414d..8c53a3747 100644 --- a/rpc/jsonrpc/server/http_json_handler_test.go +++ b/rpc/jsonrpc/server/http_json_handler_test.go @@ -1,6 +1,7 @@ package server import ( + "context" "encoding/json" "io" "net/http" @@ -17,8 +18,8 @@ import ( func testMux() *http.ServeMux { funcMap := map[string]*RPCFunc{ - "c": NewRPCFunc(func(ctx *rpctypes.Context, s string, i int) (string, error) { return "foo", nil }, "s,i", false), - "block": NewRPCFunc(func(ctx *rpctypes.Context, h int) (string, error) { return "block", nil }, "height", true), + "c": NewRPCFunc(func(ctx context.Context, s string, i int) (string, error) { return "foo", nil }, "s,i", false), + "block": NewRPCFunc(func(ctx context.Context, h int) (string, error) { return "block", nil }, "height", true), } mux := http.NewServeMux() logger := log.NewNopLogger() diff --git a/rpc/jsonrpc/server/http_uri_handler.go b/rpc/jsonrpc/server/http_uri_handler.go index 9fb5c1cde..d9e8b0cbb 100644 --- a/rpc/jsonrpc/server/http_uri_handler.go +++ b/rpc/jsonrpc/server/http_uri_handler.go @@ -39,7 +39,7 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit return func(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP HANDLER", "req", dumpHTTPRequest(r)) - ctx := &rpctypes.Context{HTTPReq: r} + ctx := rpctypes.WithCallInfo(r.Context(), &rpctypes.CallInfo{HTTPRequest: r}) args := []reflect.Value{reflect.ValueOf(ctx)} fnArgs, err := httpParamsToArgs(rpcFunc, r) diff --git a/rpc/jsonrpc/server/parse_test.go b/rpc/jsonrpc/server/parse_test.go index 6e7464739..ceb0e2020 100644 --- a/rpc/jsonrpc/server/parse_test.go +++ b/rpc/jsonrpc/server/parse_test.go @@ -1,6 +1,7 @@ package server import ( + "context" "encoding/json" "fmt" "net/http" @@ -10,7 +11,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/tendermint/tendermint/libs/bytes" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) func TestParseJSONMap(t *testing.T) { @@ -134,7 +134,7 @@ func TestParseJSONArray(t *testing.T) { } func TestParseJSONRPC(t *testing.T) { - demo := func(ctx *rpctypes.Context, height int, name string) {} + demo := func(ctx context.Context, height int, name string) {} call := NewRPCFunc(demo, "height,name", false) cases := []struct { @@ -171,7 +171,7 @@ func TestParseJSONRPC(t *testing.T) { } func TestParseURI(t *testing.T) { - demo := func(ctx *rpctypes.Context, height int, name string) {} + demo := func(ctx context.Context, height int, name string) {} call := NewRPCFunc(demo, "height,name", false) cases := []struct { diff --git a/rpc/jsonrpc/server/ws_handler.go b/rpc/jsonrpc/server/ws_handler.go index cfba6d13a..6705adb81 100644 --- a/rpc/jsonrpc/server/ws_handler.go +++ b/rpc/jsonrpc/server/ws_handler.go @@ -369,8 +369,11 @@ func (wsc *wsConnection) readRoutine(ctx context.Context) { continue } - ctx := &rpctypes.Context{JSONReq: &request, WSConn: wsc} - args := []reflect.Value{reflect.ValueOf(ctx)} + fctx := rpctypes.WithCallInfo(wsc.Context(), &rpctypes.CallInfo{ + RPCRequest: &request, + WSConn: wsc, + }) + args := []reflect.Value{reflect.ValueOf(fctx)} if len(request.Params) > 0 { fnArgs, err := jsonParamsToArgs(rpcFunc, request.Params) if err != nil { diff --git a/rpc/jsonrpc/server/ws_handler_test.go b/rpc/jsonrpc/server/ws_handler_test.go index 00d6a18a5..4bd8d72a0 100644 --- a/rpc/jsonrpc/server/ws_handler_test.go +++ b/rpc/jsonrpc/server/ws_handler_test.go @@ -1,6 +1,7 @@ package server import ( + "context" "net/http" "net/http/httptest" "testing" @@ -46,7 +47,7 @@ func TestWebsocketManagerHandler(t *testing.T) { func newWSServer(t *testing.T, logger log.Logger) *httptest.Server { funcMap := map[string]*RPCFunc{ - "c": NewWSRPCFunc(func(ctx *rpctypes.Context, s string, i int) (string, error) { return "foo", nil }, "s,i"), + "c": NewWSRPCFunc(func(ctx context.Context, s string, i int) (string, error) { return "foo", nil }, "s,i"), } wm := NewWebsocketManager(funcMap) diff --git a/rpc/jsonrpc/test/main.go b/rpc/jsonrpc/test/main.go index 4517f0298..524acc383 100644 --- a/rpc/jsonrpc/test/main.go +++ b/rpc/jsonrpc/test/main.go @@ -10,14 +10,13 @@ import ( "github.com/tendermint/tendermint/libs/log" rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" - rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" ) var routes = map[string]*rpcserver.RPCFunc{ "hello_world": rpcserver.NewRPCFunc(HelloWorld, "name,num", false), } -func HelloWorld(ctx *rpctypes.Context, name string, num int) (Result, error) { +func HelloWorld(ctx context.Context, name string, num int) (Result, error) { return Result{fmt.Sprintf("hi %s %d", name, num)}, nil } diff --git a/rpc/jsonrpc/types/types.go b/rpc/jsonrpc/types/types.go index a44faf92f..d13c2b842 100644 --- a/rpc/jsonrpc/types/types.go +++ b/rpc/jsonrpc/types/types.go @@ -250,52 +250,46 @@ type WSRPCConnection interface { Context() context.Context } -// Context is the first parameter for all functions. It carries a json-rpc -// request, http request and websocket connection. -// -// - JSONReq is non-nil when JSONRPC is called over websocket or HTTP. -// - WSConn is non-nil when we're connected via a websocket. -// - HTTPReq is non-nil when URI or JSONRPC is called over HTTP. -type Context struct { - // json-rpc request - JSONReq *RPCRequest - // websocket connection - WSConn WSRPCConnection - // http request - HTTPReq *http.Request +// CallInfo carries JSON-RPC request metadata for RPC functions invoked via +// JSON-RPC. It can be recovered from the context with GetCallInfo. +type CallInfo struct { + RPCRequest *RPCRequest // non-nil for requests via HTTP or websocket + HTTPRequest *http.Request // non-nil for requests via HTTP + WSConn WSRPCConnection // non-nil for requests via websocket } -// RemoteAddr returns the remote address (usually a string "IP:port"). -// If neither HTTPReq nor WSConn is set, an empty string is returned. -// HTTP: -// http.Request#RemoteAddr -// WS: -// result of GetRemoteAddr -func (ctx *Context) RemoteAddr() string { - if ctx.HTTPReq != nil { - return ctx.HTTPReq.RemoteAddr - } else if ctx.WSConn != nil { - return ctx.WSConn.GetRemoteAddr() +type callInfoKey struct{} + +// WithCallInfo returns a child context of ctx with the ci attached. +func WithCallInfo(ctx context.Context, ci *CallInfo) context.Context { + return context.WithValue(ctx, callInfoKey{}, ci) +} + +// GetCallInfo returns the CallInfo record attached to ctx, or nil if ctx does +// not contain a call record. +func GetCallInfo(ctx context.Context) *CallInfo { + if v := ctx.Value(callInfoKey{}); v != nil { + return v.(*CallInfo) + } + return nil +} + +// RemoteAddr returns the remote address (usually a string "IP:port"). If +// neither HTTPRequest nor WSConn is set, an empty string is returned. +// +// For HTTP requests, this reports the request's RemoteAddr. +// For websocket requests, this reports the connection's GetRemoteAddr. +func (ci *CallInfo) RemoteAddr() string { + if ci == nil { + return "" + } else if ci.HTTPRequest != nil { + return ci.HTTPRequest.RemoteAddr + } else if ci.WSConn != nil { + return ci.WSConn.GetRemoteAddr() } return "" } -// Context returns the request's context. -// The returned context is always non-nil; it defaults to the background context. -// HTTP: -// The context is canceled when the client's connection closes, the request -// is canceled (with HTTP/2), or when the ServeHTTP method returns. -// WS: -// The context is canceled when the client's connections closes. -func (ctx *Context) Context() context.Context { - if ctx.HTTPReq != nil { - return ctx.HTTPReq.Context() - } else if ctx.WSConn != nil { - return ctx.WSConn.Context() - } - return context.Background() -} - //---------------------------------------- // SOCKETS From 841629f5b7223825601263002f8ec92214db4489 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 11 Jan 2022 15:09:19 -0500 Subject: [PATCH 16/27] privval: improve client shutdown to prevent resource leak (#7544) --- privval/retry_signer_client.go | 8 ++++---- privval/signer_client.go | 21 +++++++++++++-------- privval/signer_client_test.go | 7 ++++++- privval/signer_dialer_endpoint.go | 15 +++++++++++++-- privval/signer_endpoint.go | 5 ++++- privval/signer_listener_endpoint.go | 14 +++++++------- privval/signer_listener_endpoint_test.go | 8 ++++++++ privval/signer_server.go | 2 +- 8 files changed, 56 insertions(+), 24 deletions(-) diff --git a/privval/retry_signer_client.go b/privval/retry_signer_client.go index ccd9834e4..6dacc9a28 100644 --- a/privval/retry_signer_client.go +++ b/privval/retry_signer_client.go @@ -34,15 +34,15 @@ func (sc *RetrySignerClient) IsConnected() bool { return sc.next.IsConnected() } -func (sc *RetrySignerClient) WaitForConnection(maxWait time.Duration) error { - return sc.next.WaitForConnection(maxWait) +func (sc *RetrySignerClient) WaitForConnection(ctx context.Context, maxWait time.Duration) error { + return sc.next.WaitForConnection(ctx, maxWait) } //-------------------------------------------------------- // Implement PrivValidator -func (sc *RetrySignerClient) Ping() error { - return sc.next.Ping() +func (sc *RetrySignerClient) Ping(ctx context.Context) error { + return sc.next.Ping(ctx) } func (sc *RetrySignerClient) GetPubKey(ctx context.Context) (crypto.PubKey, error) { diff --git a/privval/signer_client.go b/privval/signer_client.go index 981b4e175..3247a74b7 100644 --- a/privval/signer_client.go +++ b/privval/signer_client.go @@ -41,7 +41,12 @@ func NewSignerClient(ctx context.Context, endpoint *SignerListenerEndpoint, chai // Close closes the underlying connection func (sc *SignerClient) Close() error { - return sc.endpoint.Close() + err := sc.endpoint.Stop() + cerr := sc.endpoint.Close() + if err != nil { + return err + } + return cerr } // IsConnected indicates with the signer is connected to a remote signing service @@ -50,16 +55,16 @@ func (sc *SignerClient) IsConnected() bool { } // WaitForConnection waits maxWait for a connection or returns a timeout error -func (sc *SignerClient) WaitForConnection(maxWait time.Duration) error { - return sc.endpoint.WaitForConnection(maxWait) +func (sc *SignerClient) WaitForConnection(ctx context.Context, maxWait time.Duration) error { + return sc.endpoint.WaitForConnection(ctx, maxWait) } //-------------------------------------------------------- // Implement PrivValidator // Ping sends a ping request to the remote signer -func (sc *SignerClient) Ping() error { - response, err := sc.endpoint.SendRequest(mustWrapMsg(&privvalproto.PingRequest{})) +func (sc *SignerClient) Ping(ctx context.Context) error { + response, err := sc.endpoint.SendRequest(ctx, mustWrapMsg(&privvalproto.PingRequest{})) if err != nil { sc.logger.Error("SignerClient::Ping", "err", err) return nil @@ -76,7 +81,7 @@ func (sc *SignerClient) Ping() error { // GetPubKey retrieves a public key from a remote signer // returns an error if client is not able to provide the key func (sc *SignerClient) GetPubKey(ctx context.Context) (crypto.PubKey, error) { - response, err := sc.endpoint.SendRequest(mustWrapMsg(&privvalproto.PubKeyRequest{ChainId: sc.chainID})) + response, err := sc.endpoint.SendRequest(ctx, mustWrapMsg(&privvalproto.PubKeyRequest{ChainId: sc.chainID})) if err != nil { return nil, fmt.Errorf("send: %w", err) } @@ -99,7 +104,7 @@ func (sc *SignerClient) GetPubKey(ctx context.Context) (crypto.PubKey, error) { // SignVote requests a remote signer to sign a vote func (sc *SignerClient) SignVote(ctx context.Context, chainID string, vote *tmproto.Vote) error { - response, err := sc.endpoint.SendRequest(mustWrapMsg(&privvalproto.SignVoteRequest{Vote: vote, ChainId: chainID})) + response, err := sc.endpoint.SendRequest(ctx, mustWrapMsg(&privvalproto.SignVoteRequest{Vote: vote, ChainId: chainID})) if err != nil { return err } @@ -119,7 +124,7 @@ func (sc *SignerClient) SignVote(ctx context.Context, chainID string, vote *tmpr // SignProposal requests a remote signer to sign a proposal func (sc *SignerClient) SignProposal(ctx context.Context, chainID string, proposal *tmproto.Proposal) error { - response, err := sc.endpoint.SendRequest(mustWrapMsg( + response, err := sc.endpoint.SendRequest(ctx, mustWrapMsg( &privvalproto.SignProposalRequest{Proposal: proposal, ChainId: chainID}, )) if err != nil { diff --git a/privval/signer_client_test.go b/privval/signer_client_test.go index a7cddbd6e..6f90095c1 100644 --- a/privval/signer_client_test.go +++ b/privval/signer_client_test.go @@ -57,6 +57,7 @@ func getSignerTestCases(ctx context.Context, t *testing.T, logger log.Logger) [] signerServer: ss, }) t.Cleanup(ss.Wait) + t.Cleanup(sc.endpoint.Wait) } return testCases @@ -72,10 +73,14 @@ func TestSignerClose(t *testing.T) { for _, tc := range getSignerTestCases(bctx, t, logger) { t.Run(tc.name, func(t *testing.T) { + t.Cleanup(leaktest.Check(t)) + defer tc.closer() assert.NoError(t, tc.signerClient.Close()) assert.NoError(t, tc.signerServer.Stop()) + t.Cleanup(tc.signerClient.endpoint.Wait) + t.Cleanup(tc.signerServer.Wait) }) } } @@ -89,7 +94,7 @@ func TestSignerPing(t *testing.T) { logger := log.NewTestingLogger(t) for _, tc := range getSignerTestCases(ctx, t, logger) { - err := tc.signerClient.Ping() + err := tc.signerClient.Ping(ctx) assert.NoError(t, err) } } diff --git a/privval/signer_dialer_endpoint.go b/privval/signer_dialer_endpoint.go index 76b3bd501..b291a7ef5 100644 --- a/privval/signer_dialer_endpoint.go +++ b/privval/signer_dialer_endpoint.go @@ -74,20 +74,31 @@ func NewSignerDialerEndpoint( func (sd *SignerDialerEndpoint) OnStart(context.Context) error { return nil } func (sd *SignerDialerEndpoint) OnStop() {} -func (sd *SignerDialerEndpoint) ensureConnection() error { +func (sd *SignerDialerEndpoint) ensureConnection(ctx context.Context) error { if sd.IsConnected() { return nil } + timer := time.NewTimer(0) + defer timer.Stop() retries := 0 for retries < sd.maxConnRetries { + if err := ctx.Err(); err != nil { + return err + } conn, err := sd.dialer() if err != nil { retries++ sd.logger.Debug("SignerDialer: Reconnection failed", "retries", retries, "max", sd.maxConnRetries, "err", err) + // Wait between retries - time.Sleep(sd.retryWait) + timer.Reset(sd.retryWait) + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + } } else { sd.SetConnection(conn) sd.logger.Debug("SignerDialer: Connection Ready") diff --git a/privval/signer_endpoint.go b/privval/signer_endpoint.go index 5cf4f7be7..8810bdf85 100644 --- a/privval/signer_endpoint.go +++ b/privval/signer_endpoint.go @@ -1,6 +1,7 @@ package privval import ( + "context" "fmt" "net" "sync" @@ -54,11 +55,13 @@ func (se *signerEndpoint) GetAvailableConnection(connectionAvailableCh chan net. } // TryGetConnection retrieves a connection if it is already available -func (se *signerEndpoint) WaitConnection(connectionAvailableCh chan net.Conn, maxWait time.Duration) error { +func (se *signerEndpoint) WaitConnection(ctx context.Context, connectionAvailableCh chan net.Conn, maxWait time.Duration) error { se.connMtx.Lock() defer se.connMtx.Unlock() select { + case <-ctx.Done(): + return ctx.Err() case se.conn = <-connectionAvailableCh: case <-time.After(maxWait): return ErrConnectionTimeout diff --git a/privval/signer_listener_endpoint.go b/privval/signer_listener_endpoint.go index ff2c0b7c2..12c915973 100644 --- a/privval/signer_listener_endpoint.go +++ b/privval/signer_listener_endpoint.go @@ -99,18 +99,18 @@ func (sl *SignerListenerEndpoint) OnStop() { } // WaitForConnection waits maxWait for a connection or returns a timeout error -func (sl *SignerListenerEndpoint) WaitForConnection(maxWait time.Duration) error { +func (sl *SignerListenerEndpoint) WaitForConnection(ctx context.Context, maxWait time.Duration) error { sl.instanceMtx.Lock() defer sl.instanceMtx.Unlock() - return sl.ensureConnection(maxWait) + return sl.ensureConnection(ctx, maxWait) } // SendRequest ensures there is a connection, sends a request and waits for a response -func (sl *SignerListenerEndpoint) SendRequest(request privvalproto.Message) (*privvalproto.Message, error) { +func (sl *SignerListenerEndpoint) SendRequest(ctx context.Context, request privvalproto.Message) (*privvalproto.Message, error) { sl.instanceMtx.Lock() defer sl.instanceMtx.Unlock() - err := sl.ensureConnection(sl.timeoutAccept) + err := sl.ensureConnection(ctx, sl.timeoutAccept) if err != nil { return nil, err } @@ -131,7 +131,7 @@ func (sl *SignerListenerEndpoint) SendRequest(request privvalproto.Message) (*pr return &res, nil } -func (sl *SignerListenerEndpoint) ensureConnection(maxWait time.Duration) error { +func (sl *SignerListenerEndpoint) ensureConnection(ctx context.Context, maxWait time.Duration) error { if sl.IsConnected() { return nil } @@ -144,7 +144,7 @@ func (sl *SignerListenerEndpoint) ensureConnection(maxWait time.Duration) error // block until connected or timeout sl.logger.Info("SignerListener: Blocking for connection") sl.triggerConnect() - return sl.WaitConnection(sl.connectionAvailableCh, maxWait) + return sl.WaitConnection(ctx, sl.connectionAvailableCh, maxWait) } func (sl *SignerListenerEndpoint) acceptNewConnection() (net.Conn, error) { @@ -207,7 +207,7 @@ func (sl *SignerListenerEndpoint) pingLoop(ctx context.Context) { select { case <-sl.pingTimer.C: { - _, err := sl.SendRequest(mustWrapMsg(&privvalproto.PingRequest{})) + _, err := sl.SendRequest(ctx, mustWrapMsg(&privvalproto.PingRequest{})) if err != nil { sl.logger.Error("SignerListener: Ping timeout") sl.triggerReconnect() diff --git a/privval/signer_listener_endpoint_test.go b/privval/signer_listener_endpoint_test.go index 47fe812c9..148c6acfb 100644 --- a/privval/signer_listener_endpoint_test.go +++ b/privval/signer_listener_endpoint_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/fortytw2/leaktest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -89,6 +90,8 @@ func TestSignerRemoteRetryTCPOnly(t *testing.T) { } func TestRetryConnToRemoteSigner(t *testing.T) { + t.Cleanup(leaktest.Check(t)) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -102,6 +105,7 @@ func TestRetryConnToRemoteSigner(t *testing.T) { thisConnTimeout = testTimeoutReadWrite listenerEndpoint = newSignerListenerEndpoint(t, logger, tc.addr, thisConnTimeout) ) + t.Cleanup(listenerEndpoint.Wait) dialerEndpoint := NewSignerDialerEndpoint( logger, @@ -116,6 +120,8 @@ func TestRetryConnToRemoteSigner(t *testing.T) { require.NoError(t, signerServer.Start(ctx)) assert.True(t, signerServer.IsRunning()) + t.Cleanup(signerServer.Wait) + <-endpointIsOpenCh if err := signerServer.Stop(); err != nil { t.Error(err) @@ -130,6 +136,8 @@ func TestRetryConnToRemoteSigner(t *testing.T) { // let some pings pass require.NoError(t, signerServer2.Start(ctx)) assert.True(t, signerServer2.IsRunning()) + t.Cleanup(signerServer2.Wait) + t.Cleanup(func() { _ = signerServer2.Stop() }) // give the client some time to re-establish the conn to the remote signer // should see sth like this in the logs: diff --git a/privval/signer_server.go b/privval/signer_server.go index e98d78b75..4945b8150 100644 --- a/privval/signer_server.go +++ b/privval/signer_server.go @@ -97,7 +97,7 @@ func (ss *SignerServer) serviceLoop(ctx context.Context) { case <-ctx.Done(): return default: - if err := ss.endpoint.ensureConnection(); err != nil { + if err := ss.endpoint.ensureConnection(ctx); err != nil { return } ss.servicePendingRequest(ctx) From cc51bf758796937de8f771cf7f9d5a62f58f186e Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 11 Jan 2022 16:39:31 -0500 Subject: [PATCH 17/27] tests: remove in-test logging (#7558) --- internal/consensus/byzantine_test.go | 6 ------ internal/consensus/invalid_test.go | 1 - internal/consensus/mempool_test.go | 1 - internal/consensus/replay_test.go | 1 - internal/p2p/pex/reactor_test.go | 13 +------------ privval/signer_client_test.go | 2 -- privval/signer_listener_endpoint_test.go | 1 - 7 files changed, 1 insertion(+), 24 deletions(-) diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index b4aeaa4b9..742beecee 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -139,7 +139,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { i := 0 for _, ps := range bzReactor.peers { if i < len(bzReactor.peers)/2 { - bzNodeState.logger.Info("signed and pushed vote", "vote", prevote1, "peer", ps.peerID) require.NoError(t, bzReactor.voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, @@ -148,7 +147,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { }, })) } else { - bzNodeState.logger.Info("signed and pushed vote", "vote", prevote2, "peer", ps.peerID) require.NoError(t, bzReactor.voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, @@ -161,7 +159,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { i++ } } else { - bzNodeState.logger.Info("behaving normally") bzNodeState.defaultDoPrevote(ctx, height, round) } } @@ -173,7 +170,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { lazyNodeState := states[1] lazyNodeState.decideProposal = func(ctx context.Context, height int64, round int32) { - lazyNodeState.logger.Info("Lazy Proposer proposing condensed commit") require.NotNil(t, lazyNodeState.privValidator) var commit *types.Commit @@ -227,8 +223,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { lazyNodeState.Height, lazyNodeState.Round, part, }, ""}) } - lazyNodeState.logger.Info("Signed proposal", "height", height, "round", round, "proposal", proposal) - lazyNodeState.logger.Debug(fmt.Sprintf("Signed proposal block: %v", block)) } else if !lazyNodeState.replayMode { lazyNodeState.logger.Error("enterPropose: Error signing proposal", "height", height, "round", round, "err", err) } diff --git a/internal/consensus/invalid_test.go b/internal/consensus/invalid_test.go index 1b3636f02..e06e51a61 100644 --- a/internal/consensus/invalid_test.go +++ b/internal/consensus/invalid_test.go @@ -123,7 +123,6 @@ func invalidDoPrevoteFunc( cs.mtx.Unlock() for _, ps := range r.peers { - cs.logger.Info("sending bad vote", "block", blockHash, "peer", ps.peerID) require.NoError(t, r.voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.Vote{ diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index dc4e941a0..52df2c1f3 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -99,7 +99,6 @@ func TestMempoolProgressInHigherRound(t *testing.T) { if cs.Height == 2 && cs.Round == 0 { // dont set the proposal in round 0 so we timeout and // go to next round - cs.logger.Info("Ignoring set proposal at height 2, round 0") return nil } return cs.defaultSetProposal(proposal) diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index 0a01d00a9..dc05cc226 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -696,7 +696,6 @@ func TestMockProxyApp(t *testing.T) { if txRes.Code == abci.CodeTypeOK { validTxs++ } else { - logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log) invalidTxs++ } abciRes.DeliverTxs[txIndex] = txRes diff --git a/internal/p2p/pex/reactor_test.go b/internal/p2p/pex/reactor_test.go index 451ec37c1..872d49701 100644 --- a/internal/p2p/pex/reactor_test.go +++ b/internal/p2p/pex/reactor_test.go @@ -487,7 +487,6 @@ func (r *reactorTestSuite) listenFor( } func (r *reactorTestSuite) listenForRequest(ctx context.Context, t *testing.T, fromNode, toNode int, waitPeriod time.Duration) { - r.logger.Info("Listening for request", "from", fromNode, "to", toNode) to, from := r.checkNodePair(t, toNode, fromNode) conditional := func(msg *p2p.Envelope) bool { _, ok := msg.Message.(*p2pproto.PexRequest) @@ -508,7 +507,7 @@ func (r *reactorTestSuite) pingAndlistenForNAddresses( addresses int, ) { t.Helper() - r.logger.Info("Listening for addresses", "from", fromNode, "to", toNode) + to, from := r.checkNodePair(t, toNode, fromNode) conditional := func(msg *p2p.Envelope) bool { _, ok := msg.Message.(*p2pproto.PexResponse) @@ -541,11 +540,9 @@ func (r *reactorTestSuite) listenForResponse( waitPeriod time.Duration, addresses []p2pproto.PexAddress, ) { - r.logger.Info("Listening for response", "from", fromNode, "to", toNode) to, from := r.checkNodePair(t, toNode, fromNode) conditional := func(msg *p2p.Envelope) bool { _, ok := msg.Message.(*p2pproto.PexResponse) - r.logger.Info("message", msg, "ok", ok) return ok && msg.From == from } assertion := func(t *testing.T, msg *p2p.Envelope) bool { @@ -658,7 +655,6 @@ func (r *reactorTestSuite) connectN(ctx context.Context, t *testing.T, n int) { func (r *reactorTestSuite) connectPeers(ctx context.Context, t *testing.T, sourceNode, targetNode int) { t.Helper() node1, node2 := r.checkNodePair(t, sourceNode, targetNode) - r.logger.Info("connecting peers", "sourceNode", sourceNode, "targetNode", targetNode) n1 := r.network.Nodes[node1] if n1 == nil { @@ -676,16 +672,12 @@ func (r *reactorTestSuite) connectPeers(ctx context.Context, t *testing.T, sourc targetSub := n2.PeerManager.Subscribe(ctx) sourceAddress := n1.NodeAddress - r.logger.Debug("source address", "address", sourceAddress) targetAddress := n2.NodeAddress - r.logger.Debug("target address", "address", targetAddress) added, err := n1.PeerManager.Add(targetAddress) require.NoError(t, err) if !added { - r.logger.Debug("nodes already know about one another", - "sourceNode", sourceNode, "targetNode", targetNode) return } @@ -695,19 +687,16 @@ func (r *reactorTestSuite) connectPeers(ctx context.Context, t *testing.T, sourc NodeID: node1, Status: p2p.PeerStatusUp, }, peerUpdate) - r.logger.Debug("target connected with source") case <-time.After(2 * time.Second): require.Fail(t, "timed out waiting for peer", "%v accepting %v", targetNode, sourceNode) } - select { case peerUpdate := <-sourceSub.Updates(): require.Equal(t, p2p.PeerUpdate{ NodeID: node2, Status: p2p.PeerStatusUp, }, peerUpdate) - r.logger.Debug("source connected with target") case <-time.After(2 * time.Second): require.Fail(t, "timed out waiting for peer", "%v dialing %v", sourceNode, targetNode) diff --git a/privval/signer_client_test.go b/privval/signer_client_test.go index 6f90095c1..2867d7be5 100644 --- a/privval/signer_client_test.go +++ b/privval/signer_client_test.go @@ -303,9 +303,7 @@ func TestSignerVoteKeepAlive(t *testing.T) { // in this particular case, we use the dialer logger to ensure that // test messages are properly interleaved in the test logs - tc.signerServer.endpoint.logger.Debug("TEST: Forced Wait -------------------------------------------------") time.Sleep(testTimeoutReadWrite * 3) - tc.signerServer.endpoint.logger.Debug("TEST: Forced Wait DONE---------------------------------------------") require.NoError(t, tc.mockPV.SignVote(ctx, tc.chainID, want.ToProto())) require.NoError(t, tc.signerClient.SignVote(ctx, tc.chainID, have.ToProto())) diff --git a/privval/signer_listener_endpoint_test.go b/privval/signer_listener_endpoint_test.go index 148c6acfb..cf5567561 100644 --- a/privval/signer_listener_endpoint_test.go +++ b/privval/signer_listener_endpoint_test.go @@ -152,7 +152,6 @@ func newSignerListenerEndpoint(t *testing.T, logger log.Logger, addr string, tim proto, address := tmnet.ProtocolAndAddress(addr) ln, err := net.Listen(proto, address) - logger.Info("SignerListener: Listening", "proto", proto, "address", address) require.NoError(t, err) var listener net.Listener From 4d113364755c37630ea1d14e7e6202409e8706f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jan 2022 14:25:23 +0000 Subject: [PATCH 18/27] build(deps): Bump github.com/BurntSushi/toml from 0.4.1 to 1.0.0 (#7562) Bumps [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) from 0.4.1 to 1.0.0.
Release notes

Sourced from github.com/BurntSushi/toml's releases.

v1.0.0

This release adds much more detailed errors, support for the toml.Marshaler interface, and several fixes.

There is no special meaning in the jump to v1.0; the 0.x releases were always treated as if they're 1.x with regards to compatibility; the versioning scheme for this library predates the release of modules.

New features

  • Error reporting is much improved; the reported position of errors should now always be correct and the library can print more detailed errors (#299, #332)

    Decode always return a toml.ParseError, which has three methods:

    • Error() behaves as before and shows a single concise line with the error.

    • ErrorWithLocation() shows the same error, but also shows the line the error occurred at, similar to e.g. clang or the Rust compiler.

    • ErrorWithUsage() is the same as ErrorWithPosition(), but may also show a longer usage guidance message. This isn't always present (in which case it behaves identical to ErrorWithPosition()), but it should be present for most common mistakes and sources of confusion.

    Which error the correct one to use is depends on your application and preferences; in general I would recommend using at least ErrorWithPosition() for user-facing errors, as it's much more helpful for users of any skill level. If your users are likely to be non-technical then ErrorWithUsage() is probably a good idea; I did my best to avoid technical jargon such as "newline" and phrase things in a way that's understandable by most people not intimately familiar with these sort of things.

    Additionally, the TOML key that fialed should now always be reported in all errors.

  • Add toml.Marshaler interface. This can be used if you want full control over how something is marshalled as TOML, similar to json.Marshaler etc. This takes precedence over encoding.TextMarshaler. (#327)

  • Allow TOML integers to be decoded to a Go float (#325)

    Previously int = 42 could only be decoded to an int* type; now this can also be decoded in a float type as long as it can be represented without loss of data.

Fixes

  • Key.String() is now quoted when needed (#333)

  • Fix decoding of nested structs on 32bit platforms (#314)

  • Empty slices are now always []T{} rather than nil, which was the behaviour in v0.3.1 and before. While they are identical for most purposes, encoding/json encodes them different ([] vs. null), making it an (accidentally) incompatible change (#339)

Commits
  • 4272474 Reject control characters everywhere
  • 9bbaaec Update toml-test
  • 8a54f3e Merge TestDecodeInterfaceSlice in TestDecodeSlices
  • 9515b92 Decode S=[] into a non-nil []interface{}. (#339)
  • 7d0236f Make sure quoted keys with dots work well (#333)
  • ff0a3f8 Add back build tags for toml-test files
  • 7356d5f Few staticcheck fixes
  • b1471ff Don't allow "0_0"
  • 847ee8a Update toml-test
  • 4619257 Clearer errors when decoding to invalid types (#332)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/BurntSushi/toml&package-manager=go_modules&previous-version=0.4.1&new-version=1.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index c19812f12..556b6fa69 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/tendermint/tendermint go 1.17 require ( - github.com/BurntSushi/toml v0.4.1 + github.com/BurntSushi/toml v1.0.0 github.com/adlio/schema v1.2.3 github.com/btcsuite/btcd v0.22.0-beta github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce diff --git a/go.sum b/go.sum index 124145277..d02e70443 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,9 @@ github.com/Antonboom/nilnil v0.1.0/go.mod h1:PhHLvRPSghY5Y7mX4TW+BHZQYo1A8flE5H2 github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= +github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= From 46f56fcea52510adeaa6e5a82cff226c200ef19d Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 12:33:17 -0500 Subject: [PATCH 19/27] node: move seed node implementation to its own file (#7566) --- node/node.go | 152 --------------------------------------------- node/seed.go | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 152 deletions(-) create mode 100644 node/seed.go diff --git a/node/node.go b/node/node.go index e2951f83c..7429c07db 100644 --- a/node/node.go +++ b/node/node.go @@ -82,26 +82,6 @@ type nodeImpl struct { prometheusSrv *http.Server } -type seedNodeImpl struct { - service.BaseService - logger log.Logger - - // config - config *config.Config - genesisDoc *types.GenesisDoc // initial validator set - - // network - peerManager *p2p.PeerManager - router *p2p.Router - nodeInfo types.NodeInfo - nodeKey types.NodeKey // our node privkey - isListening bool - - // services - pexReactor service.Service // for exchanging peer addresses - shutdownOps closer -} - // newDefaultNode returns a Tendermint node with default settings for the // PrivValidator, ClientCreator, GenesisDoc, and DBProvider. // It implements NodeProvider. @@ -462,138 +442,6 @@ func makeNode( return node, nil } -// makeSeedNode returns a new seed node, containing only p2p, pex reactor -func makeSeedNode( - ctx context.Context, - cfg *config.Config, - dbProvider config.DBProvider, - nodeKey types.NodeKey, - genesisDocProvider genesisDocProvider, - logger log.Logger, -) (service.Service, error) { - if !cfg.P2P.PexReactor { - return nil, errors.New("cannot run seed nodes with PEX disabled") - } - - genDoc, err := genesisDocProvider() - if err != nil { - return nil, err - } - - state, err := sm.MakeGenesisState(genDoc) - if err != nil { - return nil, err - } - - nodeInfo, err := makeSeedNodeInfo(cfg, nodeKey, genDoc, state) - if err != nil { - return nil, err - } - - // Setup Transport and Switch. - p2pMetrics := p2p.PrometheusMetrics(cfg.Instrumentation.Namespace, "chain_id", genDoc.ChainID) - - peerManager, closer, err := createPeerManager(cfg, dbProvider, nodeKey.ID) - if err != nil { - return nil, combineCloseError( - fmt.Errorf("failed to create peer manager: %w", err), - closer) - } - - router, err := createRouter(ctx, logger, p2pMetrics, nodeInfo, nodeKey, - peerManager, cfg, nil) - if err != nil { - return nil, combineCloseError( - fmt.Errorf("failed to create router: %w", err), - closer) - } - - pexReactor, err := pex.NewReactor(ctx, logger, peerManager, router.OpenChannel, peerManager.Subscribe(ctx)) - if err != nil { - return nil, combineCloseError(err, closer) - } - - node := &seedNodeImpl{ - config: cfg, - logger: logger, - genesisDoc: genDoc, - - nodeInfo: nodeInfo, - nodeKey: nodeKey, - peerManager: peerManager, - router: router, - - shutdownOps: closer, - - pexReactor: pexReactor, - } - node.BaseService = *service.NewBaseService(logger, "SeedNode", node) - - return node, nil -} - -// OnStart starts the Seed Node. It implements service.Service. -func (n *seedNodeImpl) OnStart(ctx context.Context) error { - if n.config.RPC.PprofListenAddress != "" { - rpcCtx, rpcCancel := context.WithCancel(ctx) - srv := &http.Server{Addr: n.config.RPC.PprofListenAddress, Handler: nil} - go func() { - select { - case <-ctx.Done(): - sctx, scancel := context.WithTimeout(context.Background(), time.Second) - defer scancel() - _ = srv.Shutdown(sctx) - case <-rpcCtx.Done(): - } - }() - - go func() { - n.logger.Info("Starting pprof server", "laddr", n.config.RPC.PprofListenAddress) - - if err := srv.ListenAndServe(); err != nil { - n.logger.Error("pprof server error", "err", err) - rpcCancel() - } - }() - } - - now := tmtime.Now() - genTime := n.genesisDoc.GenesisTime - if genTime.After(now) { - n.logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime) - time.Sleep(genTime.Sub(now)) - } - - // Start the transport. - if err := n.router.Start(ctx); err != nil { - return err - } - n.isListening = true - - if n.config.P2P.PexReactor { - if err := n.pexReactor.Start(ctx); err != nil { - return err - } - } - - return nil -} - -// OnStop stops the Seed Node. It implements service.Service. -func (n *seedNodeImpl) OnStop() { - n.logger.Info("Stopping Node") - - n.pexReactor.Wait() - n.router.Wait() - n.isListening = false - - if err := n.shutdownOps(); err != nil { - if strings.TrimSpace(err.Error()) != "" { - n.logger.Error("problem shutting down additional services", "err", err) - } - } -} - // OnStart starts the Node. It implements service.Service. func (n *nodeImpl) OnStart(ctx context.Context) error { if n.config.RPC.PprofListenAddress != "" { diff --git a/node/seed.go b/node/seed.go new file mode 100644 index 000000000..ef3e61df0 --- /dev/null +++ b/node/seed.go @@ -0,0 +1,171 @@ +package node + +import ( + "context" + "errors" + "fmt" + "net/http" + "time" + + "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/internal/p2p" + "github.com/tendermint/tendermint/internal/p2p/pex" + sm "github.com/tendermint/tendermint/internal/state" + "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/libs/service" + "github.com/tendermint/tendermint/libs/strings" + tmtime "github.com/tendermint/tendermint/libs/time" + "github.com/tendermint/tendermint/types" +) + +type seedNodeImpl struct { + service.BaseService + logger log.Logger + + // config + config *config.Config + genesisDoc *types.GenesisDoc // initial validator set + + // network + peerManager *p2p.PeerManager + router *p2p.Router + nodeInfo types.NodeInfo + nodeKey types.NodeKey // our node privkey + isListening bool + + // services + pexReactor service.Service // for exchanging peer addresses + shutdownOps closer +} + +// makeSeedNode returns a new seed node, containing only p2p, pex reactor +func makeSeedNode( + ctx context.Context, + cfg *config.Config, + dbProvider config.DBProvider, + nodeKey types.NodeKey, + genesisDocProvider genesisDocProvider, + logger log.Logger, +) (service.Service, error) { + if !cfg.P2P.PexReactor { + return nil, errors.New("cannot run seed nodes with PEX disabled") + } + + genDoc, err := genesisDocProvider() + if err != nil { + return nil, err + } + + state, err := sm.MakeGenesisState(genDoc) + if err != nil { + return nil, err + } + + nodeInfo, err := makeSeedNodeInfo(cfg, nodeKey, genDoc, state) + if err != nil { + return nil, err + } + + // Setup Transport and Switch. + p2pMetrics := p2p.PrometheusMetrics(cfg.Instrumentation.Namespace, "chain_id", genDoc.ChainID) + + peerManager, closer, err := createPeerManager(cfg, dbProvider, nodeKey.ID) + if err != nil { + return nil, combineCloseError( + fmt.Errorf("failed to create peer manager: %w", err), + closer) + } + + router, err := createRouter(ctx, logger, p2pMetrics, nodeInfo, nodeKey, + peerManager, cfg, nil) + if err != nil { + return nil, combineCloseError( + fmt.Errorf("failed to create router: %w", err), + closer) + } + + pexReactor, err := pex.NewReactor(ctx, logger, peerManager, router.OpenChannel, peerManager.Subscribe(ctx)) + if err != nil { + return nil, combineCloseError(err, closer) + } + + node := &seedNodeImpl{ + config: cfg, + logger: logger, + genesisDoc: genDoc, + + nodeInfo: nodeInfo, + nodeKey: nodeKey, + peerManager: peerManager, + router: router, + + shutdownOps: closer, + + pexReactor: pexReactor, + } + node.BaseService = *service.NewBaseService(logger, "SeedNode", node) + + return node, nil +} + +// OnStart starts the Seed Node. It implements service.Service. +func (n *seedNodeImpl) OnStart(ctx context.Context) error { + if n.config.RPC.PprofListenAddress != "" { + rpcCtx, rpcCancel := context.WithCancel(ctx) + srv := &http.Server{Addr: n.config.RPC.PprofListenAddress, Handler: nil} + go func() { + select { + case <-ctx.Done(): + sctx, scancel := context.WithTimeout(context.Background(), time.Second) + defer scancel() + _ = srv.Shutdown(sctx) + case <-rpcCtx.Done(): + } + }() + + go func() { + n.logger.Info("Starting pprof server", "laddr", n.config.RPC.PprofListenAddress) + + if err := srv.ListenAndServe(); err != nil { + n.logger.Error("pprof server error", "err", err) + rpcCancel() + } + }() + } + + now := tmtime.Now() + genTime := n.genesisDoc.GenesisTime + if genTime.After(now) { + n.logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime) + time.Sleep(genTime.Sub(now)) + } + + // Start the transport. + if err := n.router.Start(ctx); err != nil { + return err + } + n.isListening = true + + if n.config.P2P.PexReactor { + if err := n.pexReactor.Start(ctx); err != nil { + return err + } + } + + return nil +} + +// OnStop stops the Seed Node. It implements service.Service. +func (n *seedNodeImpl) OnStop() { + n.logger.Info("Stopping Node") + + n.pexReactor.Wait() + n.router.Wait() + n.isListening = false + + if err := n.shutdownOps(); err != nil { + if strings.TrimSpace(err.Error()) != "" { + n.logger.Error("problem shutting down additional services", "err", err) + } + } +} From fb10d1c70538461aae618eb8fb93fbe53fc83c33 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 12:57:23 -0500 Subject: [PATCH 20/27] statesync: clarify test cleanup (#7565) --- internal/statesync/reactor_test.go | 9 ++++--- internal/statesync/syncer_test.go | 43 +++++++++++++++++++----------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index 4ff02d0bc..4e81d53b0 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -193,13 +193,14 @@ func setup( rts.reactor.metrics, ) + ctx, cancel := context.WithCancel(ctx) + require.NoError(t, rts.reactor.Start(ctx)) require.True(t, rts.reactor.IsRunning()) - t.Cleanup(func() { - rts.reactor.Wait() - require.False(t, rts.reactor.IsRunning()) - }) + t.Cleanup(cancel) + t.Cleanup(rts.reactor.Wait) + t.Cleanup(leaktest.Check(t)) return rts } diff --git a/internal/statesync/syncer_test.go b/internal/statesync/syncer_test.go index 3126a7688..7ce293890 100644 --- a/internal/statesync/syncer_test.go +++ b/internal/statesync/syncer_test.go @@ -133,27 +133,38 @@ func TestSyncer_SyncAny(t *testing.T) { chunkRequests := make(map[uint32]int) chunkRequestsMtx := sync.Mutex{} - var wg sync.WaitGroup - wg.Add(4) + chunkProcessDone := make(chan struct{}) go func() { - for e := range rts.chunkOutCh { - msg, ok := e.Message.(*ssproto.ChunkRequest) - assert.True(t, ok) + defer close(chunkProcessDone) + var seen int + for { + if seen >= 4 { + return + } - assert.EqualValues(t, 1, msg.Height) - assert.EqualValues(t, 1, msg.Format) - assert.LessOrEqual(t, msg.Index, uint32(len(chunks))) + select { + case <-ctx.Done(): + t.Logf("sent %d chunks", seen) + return + case e := <-rts.chunkOutCh: + msg, ok := e.Message.(*ssproto.ChunkRequest) + assert.True(t, ok) - added, err := rts.syncer.AddChunk(chunks[msg.Index]) - assert.NoError(t, err) - assert.True(t, added) + assert.EqualValues(t, 1, msg.Height) + assert.EqualValues(t, 1, msg.Format) + assert.LessOrEqual(t, msg.Index, uint32(len(chunks))) - chunkRequestsMtx.Lock() - chunkRequests[msg.Index]++ - chunkRequestsMtx.Unlock() + added, err := rts.syncer.AddChunk(chunks[msg.Index]) + assert.NoError(t, err) + assert.True(t, added) - wg.Done() + chunkRequestsMtx.Lock() + chunkRequests[msg.Index]++ + chunkRequestsMtx.Unlock() + seen++ + t.Logf("added chunk (%d of 4): %d", seen, msg.Index) + } } }() @@ -186,7 +197,7 @@ func TestSyncer_SyncAny(t *testing.T) { newState, lastCommit, err := rts.syncer.SyncAny(ctx, 0, func() error { return nil }) require.NoError(t, err) - wg.Wait() + <-chunkProcessDone chunkRequestsMtx.Lock() require.Equal(t, map[uint32]int{0: 1, 1: 2, 2: 1}, chunkRequests) From 1f5e64e5b69691b2041825e637eb2feeb8bd6e3f Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Wed, 12 Jan 2022 10:20:59 -0800 Subject: [PATCH 21/27] rpc: remove cache control settings from the HTTP server (#7568) We should not set cache-control headers on RPC responses. HTTP caching interacts poorly with resources that are expected to change frequently, or whose rate of change is unpredictable. More subtly, all calls to the POST endpoint use the same URL, which means a cacheable response from one call may actually "hide" an uncacheable response from a subsequent one. This is less of a problem for the GET endpoints, but that means the behaviour of RPCs varies depending on which HTTP method your client happens to use. Websocket requests were already marked statically uncacheable, adding yet a third combination. To address this: - Stop setting cache-control headers. - Update the tests that were checking for those headers. - Remove the flags to request cache-control. Apart from affecting the HTTP response headers, this change does not modify the behaviour of any of the RPC methods. --- internal/inspect/rpc/rpc.go | 20 +++---- internal/rpc/core/routes.go | 60 ++++++++++---------- light/proxy/routes.go | 54 +++++++++--------- rpc/jsonrpc/jsonrpc_test.go | 8 +-- rpc/jsonrpc/server/http_json_handler.go | 28 +-------- rpc/jsonrpc/server/http_json_handler_test.go | 6 +- rpc/jsonrpc/server/http_server.go | 9 +-- rpc/jsonrpc/server/http_server_test.go | 8 +-- rpc/jsonrpc/server/http_uri_handler.go | 2 +- rpc/jsonrpc/server/parse_test.go | 4 +- rpc/jsonrpc/server/rpc_func.go | 11 ++-- rpc/jsonrpc/test/main.go | 2 +- test/fuzz/rpc/jsonrpc/server/handler.go | 2 +- 13 files changed, 91 insertions(+), 123 deletions(-) diff --git a/internal/inspect/rpc/rpc.go b/internal/inspect/rpc/rpc.go index 7ed47962a..5c0d1a7e9 100644 --- a/internal/inspect/rpc/rpc.go +++ b/internal/inspect/rpc/rpc.go @@ -41,16 +41,16 @@ func Routes(cfg config.RPCConfig, s state.Store, bs state.BlockStore, es []index Logger: logger, } return core.RoutesMap{ - "blockchain": server.NewRPCFunc(env.BlockchainInfo, "minHeight,maxHeight", true), - "consensus_params": server.NewRPCFunc(env.ConsensusParams, "height", true), - "block": server.NewRPCFunc(env.Block, "height", true), - "block_by_hash": server.NewRPCFunc(env.BlockByHash, "hash", true), - "block_results": server.NewRPCFunc(env.BlockResults, "height", true), - "commit": server.NewRPCFunc(env.Commit, "height", true), - "validators": server.NewRPCFunc(env.Validators, "height,page,per_page", true), - "tx": server.NewRPCFunc(env.Tx, "hash,prove", true), - "tx_search": server.NewRPCFunc(env.TxSearch, "query,prove,page,per_page,order_by", false), - "block_search": server.NewRPCFunc(env.BlockSearch, "query,page,per_page,order_by", false), + "blockchain": server.NewRPCFunc(env.BlockchainInfo, "minHeight,maxHeight"), + "consensus_params": server.NewRPCFunc(env.ConsensusParams, "height"), + "block": server.NewRPCFunc(env.Block, "height"), + "block_by_hash": server.NewRPCFunc(env.BlockByHash, "hash"), + "block_results": server.NewRPCFunc(env.BlockResults, "height"), + "commit": server.NewRPCFunc(env.Commit, "height"), + "validators": server.NewRPCFunc(env.Validators, "height,page,per_page"), + "tx": server.NewRPCFunc(env.Tx, "hash,prove"), + "tx_search": server.NewRPCFunc(env.TxSearch, "query,prove,page,per_page,order_by"), + "block_search": server.NewRPCFunc(env.BlockSearch, "query,page,per_page,order_by"), } } diff --git a/internal/rpc/core/routes.go b/internal/rpc/core/routes.go index dd53711c3..2231ae1e5 100644 --- a/internal/rpc/core/routes.go +++ b/internal/rpc/core/routes.go @@ -17,46 +17,46 @@ func (env *Environment) GetRoutes() RoutesMap { "unsubscribe_all": rpc.NewWSRPCFunc(env.UnsubscribeAll, ""), // info API - "health": rpc.NewRPCFunc(env.Health, "", false), - "status": rpc.NewRPCFunc(env.Status, "", false), - "net_info": rpc.NewRPCFunc(env.NetInfo, "", false), - "blockchain": rpc.NewRPCFunc(env.BlockchainInfo, "minHeight,maxHeight", true), - "genesis": rpc.NewRPCFunc(env.Genesis, "", true), - "genesis_chunked": rpc.NewRPCFunc(env.GenesisChunked, "chunk", true), - "header": rpc.NewRPCFunc(env.Header, "height", true), - "header_by_hash": rpc.NewRPCFunc(env.HeaderByHash, "hash", true), - "block": rpc.NewRPCFunc(env.Block, "height", true), - "block_by_hash": rpc.NewRPCFunc(env.BlockByHash, "hash", true), - "block_results": rpc.NewRPCFunc(env.BlockResults, "height", true), - "commit": rpc.NewRPCFunc(env.Commit, "height", true), - "check_tx": rpc.NewRPCFunc(env.CheckTx, "tx", true), - "remove_tx": rpc.NewRPCFunc(env.RemoveTx, "txkey", false), - "tx": rpc.NewRPCFunc(env.Tx, "hash,prove", true), - "tx_search": rpc.NewRPCFunc(env.TxSearch, "query,prove,page,per_page,order_by", false), - "block_search": rpc.NewRPCFunc(env.BlockSearch, "query,page,per_page,order_by", false), - "validators": rpc.NewRPCFunc(env.Validators, "height,page,per_page", true), - "dump_consensus_state": rpc.NewRPCFunc(env.DumpConsensusState, "", false), - "consensus_state": rpc.NewRPCFunc(env.GetConsensusState, "", false), - "consensus_params": rpc.NewRPCFunc(env.ConsensusParams, "height", true), - "unconfirmed_txs": rpc.NewRPCFunc(env.UnconfirmedTxs, "limit", false), - "num_unconfirmed_txs": rpc.NewRPCFunc(env.NumUnconfirmedTxs, "", false), + "health": rpc.NewRPCFunc(env.Health, ""), + "status": rpc.NewRPCFunc(env.Status, ""), + "net_info": rpc.NewRPCFunc(env.NetInfo, ""), + "blockchain": rpc.NewRPCFunc(env.BlockchainInfo, "minHeight,maxHeight"), + "genesis": rpc.NewRPCFunc(env.Genesis, ""), + "genesis_chunked": rpc.NewRPCFunc(env.GenesisChunked, "chunk"), + "header": rpc.NewRPCFunc(env.Header, "height"), + "header_by_hash": rpc.NewRPCFunc(env.HeaderByHash, "hash"), + "block": rpc.NewRPCFunc(env.Block, "height"), + "block_by_hash": rpc.NewRPCFunc(env.BlockByHash, "hash"), + "block_results": rpc.NewRPCFunc(env.BlockResults, "height"), + "commit": rpc.NewRPCFunc(env.Commit, "height"), + "check_tx": rpc.NewRPCFunc(env.CheckTx, "tx"), + "remove_tx": rpc.NewRPCFunc(env.RemoveTx, "txkey"), + "tx": rpc.NewRPCFunc(env.Tx, "hash,prove"), + "tx_search": rpc.NewRPCFunc(env.TxSearch, "query,prove,page,per_page,order_by"), + "block_search": rpc.NewRPCFunc(env.BlockSearch, "query,page,per_page,order_by"), + "validators": rpc.NewRPCFunc(env.Validators, "height,page,per_page"), + "dump_consensus_state": rpc.NewRPCFunc(env.DumpConsensusState, ""), + "consensus_state": rpc.NewRPCFunc(env.GetConsensusState, ""), + "consensus_params": rpc.NewRPCFunc(env.ConsensusParams, "height"), + "unconfirmed_txs": rpc.NewRPCFunc(env.UnconfirmedTxs, "limit"), + "num_unconfirmed_txs": rpc.NewRPCFunc(env.NumUnconfirmedTxs, ""), // tx broadcast API - "broadcast_tx_commit": rpc.NewRPCFunc(env.BroadcastTxCommit, "tx", false), - "broadcast_tx_sync": rpc.NewRPCFunc(env.BroadcastTxSync, "tx", false), - "broadcast_tx_async": rpc.NewRPCFunc(env.BroadcastTxAsync, "tx", false), + "broadcast_tx_commit": rpc.NewRPCFunc(env.BroadcastTxCommit, "tx"), + "broadcast_tx_sync": rpc.NewRPCFunc(env.BroadcastTxSync, "tx"), + "broadcast_tx_async": rpc.NewRPCFunc(env.BroadcastTxAsync, "tx"), // abci API - "abci_query": rpc.NewRPCFunc(env.ABCIQuery, "path,data,height,prove", false), - "abci_info": rpc.NewRPCFunc(env.ABCIInfo, "", true), + "abci_query": rpc.NewRPCFunc(env.ABCIQuery, "path,data,height,prove"), + "abci_info": rpc.NewRPCFunc(env.ABCIInfo, ""), // evidence API - "broadcast_evidence": rpc.NewRPCFunc(env.BroadcastEvidence, "evidence", false), + "broadcast_evidence": rpc.NewRPCFunc(env.BroadcastEvidence, "evidence"), } } // AddUnsafeRoutes adds unsafe routes. func (env *Environment) AddUnsafe(routes RoutesMap) { // control API - routes["unsafe_flush_mempool"] = rpc.NewRPCFunc(env.UnsafeFlushMempool, "", false) + routes["unsafe_flush_mempool"] = rpc.NewRPCFunc(env.UnsafeFlushMempool, "") } diff --git a/light/proxy/routes.go b/light/proxy/routes.go index 4fb815b7e..6f5b3c1db 100644 --- a/light/proxy/routes.go +++ b/light/proxy/routes.go @@ -19,39 +19,39 @@ func RPCRoutes(c *lrpc.Client) map[string]*rpcserver.RPCFunc { "unsubscribe_all": rpcserver.NewWSRPCFunc(c.UnsubscribeAllWS, ""), // info API - "health": rpcserver.NewRPCFunc(makeHealthFunc(c), "", false), - "status": rpcserver.NewRPCFunc(makeStatusFunc(c), "", false), - "net_info": rpcserver.NewRPCFunc(makeNetInfoFunc(c), "", false), - "blockchain": rpcserver.NewRPCFunc(makeBlockchainInfoFunc(c), "minHeight,maxHeight", true), - "genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), "", true), - "genesis_chunked": rpcserver.NewRPCFunc(makeGenesisChunkedFunc(c), "", true), - "header": rpcserver.NewRPCFunc(makeHeaderFunc(c), "height", true), - "header_by_hash": rpcserver.NewRPCFunc(makeHeaderByHashFunc(c), "hash", true), - "block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height", true), - "block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash", true), - "block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height", true), - "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height", true), - "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove", true), - "tx_search": rpcserver.NewRPCFunc(makeTxSearchFunc(c), "query,prove,page,per_page,order_by", false), - "block_search": rpcserver.NewRPCFunc(makeBlockSearchFunc(c), "query,page,per_page,order_by", false), - "validators": rpcserver.NewRPCFunc(makeValidatorsFunc(c), "height,page,per_page", true), - "dump_consensus_state": rpcserver.NewRPCFunc(makeDumpConsensusStateFunc(c), "", false), - "consensus_state": rpcserver.NewRPCFunc(makeConsensusStateFunc(c), "", false), - "consensus_params": rpcserver.NewRPCFunc(makeConsensusParamsFunc(c), "height", true), - "unconfirmed_txs": rpcserver.NewRPCFunc(makeUnconfirmedTxsFunc(c), "limit", false), - "num_unconfirmed_txs": rpcserver.NewRPCFunc(makeNumUnconfirmedTxsFunc(c), "", false), + "health": rpcserver.NewRPCFunc(makeHealthFunc(c), ""), + "status": rpcserver.NewRPCFunc(makeStatusFunc(c), ""), + "net_info": rpcserver.NewRPCFunc(makeNetInfoFunc(c), ""), + "blockchain": rpcserver.NewRPCFunc(makeBlockchainInfoFunc(c), "minHeight,maxHeight"), + "genesis": rpcserver.NewRPCFunc(makeGenesisFunc(c), ""), + "genesis_chunked": rpcserver.NewRPCFunc(makeGenesisChunkedFunc(c), ""), + "header": rpcserver.NewRPCFunc(makeHeaderFunc(c), "height"), + "header_by_hash": rpcserver.NewRPCFunc(makeHeaderByHashFunc(c), "hash"), + "block": rpcserver.NewRPCFunc(makeBlockFunc(c), "height"), + "block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash"), + "block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height"), + "commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height"), + "tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove"), + "tx_search": rpcserver.NewRPCFunc(makeTxSearchFunc(c), "query,prove,page,per_page,order_by"), + "block_search": rpcserver.NewRPCFunc(makeBlockSearchFunc(c), "query,page,per_page,order_by"), + "validators": rpcserver.NewRPCFunc(makeValidatorsFunc(c), "height,page,per_page"), + "dump_consensus_state": rpcserver.NewRPCFunc(makeDumpConsensusStateFunc(c), ""), + "consensus_state": rpcserver.NewRPCFunc(makeConsensusStateFunc(c), ""), + "consensus_params": rpcserver.NewRPCFunc(makeConsensusParamsFunc(c), "height"), + "unconfirmed_txs": rpcserver.NewRPCFunc(makeUnconfirmedTxsFunc(c), "limit"), + "num_unconfirmed_txs": rpcserver.NewRPCFunc(makeNumUnconfirmedTxsFunc(c), ""), // tx broadcast API - "broadcast_tx_commit": rpcserver.NewRPCFunc(makeBroadcastTxCommitFunc(c), "tx", false), - "broadcast_tx_sync": rpcserver.NewRPCFunc(makeBroadcastTxSyncFunc(c), "tx", false), - "broadcast_tx_async": rpcserver.NewRPCFunc(makeBroadcastTxAsyncFunc(c), "tx", false), + "broadcast_tx_commit": rpcserver.NewRPCFunc(makeBroadcastTxCommitFunc(c), "tx"), + "broadcast_tx_sync": rpcserver.NewRPCFunc(makeBroadcastTxSyncFunc(c), "tx"), + "broadcast_tx_async": rpcserver.NewRPCFunc(makeBroadcastTxAsyncFunc(c), "tx"), // abci API - "abci_query": rpcserver.NewRPCFunc(makeABCIQueryFunc(c), "path,data,height,prove", false), - "abci_info": rpcserver.NewRPCFunc(makeABCIInfoFunc(c), "", true), + "abci_query": rpcserver.NewRPCFunc(makeABCIQueryFunc(c), "path,data,height,prove"), + "abci_info": rpcserver.NewRPCFunc(makeABCIInfoFunc(c), ""), // evidence API - "broadcast_evidence": rpcserver.NewRPCFunc(makeBroadcastEvidenceFunc(c), "evidence", false), + "broadcast_evidence": rpcserver.NewRPCFunc(makeBroadcastEvidenceFunc(c), "evidence"), } } diff --git a/rpc/jsonrpc/jsonrpc_test.go b/rpc/jsonrpc/jsonrpc_test.go index 3ad0599ed..002e0b6ab 100644 --- a/rpc/jsonrpc/jsonrpc_test.go +++ b/rpc/jsonrpc/jsonrpc_test.go @@ -53,11 +53,11 @@ type ResultEchoDataBytes struct { // Define some routes var Routes = map[string]*server.RPCFunc{ - "echo": server.NewRPCFunc(EchoResult, "arg", false), + "echo": server.NewRPCFunc(EchoResult, "arg"), "echo_ws": server.NewWSRPCFunc(EchoWSResult, "arg"), - "echo_bytes": server.NewRPCFunc(EchoBytesResult, "arg", false), - "echo_data_bytes": server.NewRPCFunc(EchoDataBytesResult, "arg", false), - "echo_int": server.NewRPCFunc(EchoIntResult, "arg", false), + "echo_bytes": server.NewRPCFunc(EchoBytesResult, "arg"), + "echo_data_bytes": server.NewRPCFunc(EchoDataBytesResult, "arg"), + "echo_int": server.NewRPCFunc(EchoIntResult, "arg"), } func EchoResult(ctx context.Context, v string) (*ResultEcho, error) { diff --git a/rpc/jsonrpc/server/http_json_handler.go b/rpc/jsonrpc/server/http_json_handler.go index 6111aa084..a66e61933 100644 --- a/rpc/jsonrpc/server/http_json_handler.go +++ b/rpc/jsonrpc/server/http_json_handler.go @@ -53,12 +53,7 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han return } - // Set the default response cache to true unless - // 1. Any RPC request rrror. - // 2. Any RPC request doesn't allow to be cached. - // 3. Any RPC request has the height argument and the value is 0 (the default). var responses []rpctypes.RPCResponse - mayCache := true for _, req := range requests { // Ignore notifications, which this service does not support. if req.ID == nil { @@ -69,25 +64,16 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han rpcFunc, ok := funcMap[req.Method] if !ok || rpcFunc.ws { responses = append(responses, rpctypes.RPCMethodNotFoundError(req.ID)) - mayCache = false continue } - if !rpcFunc.cache { - mayCache = false - } args, err := parseParams(rpcFunc, hreq, req) if err != nil { responses = append(responses, rpctypes.RPCInvalidParamsError( req.ID, fmt.Errorf("converting JSON parameters: %w", err))) - mayCache = false continue } - if hasDefaultHeight(req, args) { - mayCache = false - } - returns := rpcFunc.f.Call(args) logger.Debug("HTTPJSONRPC", "method", req.Method, "args", args, "returns", returns) result, err := unreflectResult(returns) @@ -99,24 +85,21 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han // if this already of type RPC error then forward that error case *rpctypes.RPCError: responses = append(responses, rpctypes.NewRPCErrorResponse(req.ID, e.Code, e.Message, e.Data)) - mayCache = false default: // we need to unwrap the error and parse it accordingly switch errors.Unwrap(err) { // check if the error was due to an invald request case coretypes.ErrZeroOrNegativeHeight, coretypes.ErrZeroOrNegativePerPage, coretypes.ErrPageOutOfRange, coretypes.ErrInvalidRequest: responses = append(responses, rpctypes.RPCInvalidRequestError(req.ID, err)) - mayCache = false // lastly default all remaining errors as internal errors default: // includes ctypes.ErrHeightNotAvailable and ctypes.ErrHeightExceedsChainHead responses = append(responses, rpctypes.RPCInternalError(req.ID, err)) - mayCache = false } } } if len(responses) > 0 { - if wErr := WriteRPCResponseHTTP(w, mayCache, responses...); wErr != nil { + if wErr := WriteRPCResponseHTTP(w, responses...); wErr != nil { logger.Error("failed to write responses", "err", wErr) } } @@ -288,12 +271,3 @@ func writeListOfEndpoints(w http.ResponseWriter, r *http.Request, funcMap map[st w.WriteHeader(200) w.Write(buf.Bytes()) // nolint: errcheck } - -func hasDefaultHeight(r rpctypes.RPCRequest, h []reflect.Value) bool { - switch r.Method { - case "block", "block_results", "commit", "consensus_params", "validators": - return len(h) < 2 || h[1].IsZero() - default: - return false - } -} diff --git a/rpc/jsonrpc/server/http_json_handler_test.go b/rpc/jsonrpc/server/http_json_handler_test.go index 8c53a3747..92ad1435c 100644 --- a/rpc/jsonrpc/server/http_json_handler_test.go +++ b/rpc/jsonrpc/server/http_json_handler_test.go @@ -18,8 +18,8 @@ import ( func testMux() *http.ServeMux { funcMap := map[string]*RPCFunc{ - "c": NewRPCFunc(func(ctx context.Context, s string, i int) (string, error) { return "foo", nil }, "s,i", false), - "block": NewRPCFunc(func(ctx context.Context, h int) (string, error) { return "block", nil }, "height", true), + "c": NewRPCFunc(func(ctx context.Context, s string, i int) (string, error) { return "foo", nil }, "s,i"), + "block": NewRPCFunc(func(ctx context.Context, h int) (string, error) { return "block", nil }, "height"), } mux := http.NewServeMux() logger := log.NewNopLogger() @@ -238,7 +238,7 @@ func TestRPCResponseCache(t *testing.T) { // Always expecting back a JSONRPCResponse require.True(t, statusOK(res.StatusCode), "should always return 2XX") - require.Equal(t, "max-age=31536000", res.Header.Get("Cache-control")) + require.Equal(t, "", res.Header.Get("Cache-control")) _, err := io.ReadAll(res.Body) res.Body.Close() diff --git a/rpc/jsonrpc/server/http_server.go b/rpc/jsonrpc/server/http_server.go index 5d6b3a355..a9a5ca0b8 100644 --- a/rpc/jsonrpc/server/http_server.go +++ b/rpc/jsonrpc/server/http_server.go @@ -169,7 +169,7 @@ func WriteRPCResponseHTTPError( // WriteRPCResponseHTTP marshals res as JSON (with indent) and writes it to w. // If the rpc response can be cached, add cache-control to the response header. -func WriteRPCResponseHTTP(w http.ResponseWriter, c bool, res ...rpctypes.RPCResponse) error { +func WriteRPCResponseHTTP(w http.ResponseWriter, res ...rpctypes.RPCResponse) error { var v interface{} if len(res) == 1 { v = res[0] @@ -182,10 +182,7 @@ func WriteRPCResponseHTTP(w http.ResponseWriter, c bool, res ...rpctypes.RPCResp return fmt.Errorf("json marshal: %w", err) } w.Header().Set("Content-Type", "application/json") - if c { - w.Header().Set("Cache-Control", "max-age=31536000") // expired after one year - } - w.WriteHeader(200) + w.WriteHeader(http.StatusOK) _, err = w.Write(jsonBytes) return err } @@ -225,7 +222,7 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler // If RPCResponse if res, ok := e.(rpctypes.RPCResponse); ok { - if wErr := WriteRPCResponseHTTP(rww, false, res); wErr != nil { + if wErr := WriteRPCResponseHTTP(rww, res); wErr != nil { logger.Error("failed to write response", "res", res, "err", wErr) } } else { diff --git a/rpc/jsonrpc/server/http_server_test.go b/rpc/jsonrpc/server/http_server_test.go index c546f82fc..7c114e62a 100644 --- a/rpc/jsonrpc/server/http_server_test.go +++ b/rpc/jsonrpc/server/http_server_test.go @@ -122,7 +122,7 @@ func TestWriteRPCResponseHTTP(t *testing.T) { // one argument w := httptest.NewRecorder() - err := WriteRPCResponseHTTP(w, true, rpctypes.NewRPCSuccessResponse(id, &sampleResult{"hello"})) + err := WriteRPCResponseHTTP(w, rpctypes.NewRPCSuccessResponse(id, &sampleResult{"hello"})) require.NoError(t, err) resp := w.Result() body, err := io.ReadAll(resp.Body) @@ -130,7 +130,7 @@ func TestWriteRPCResponseHTTP(t *testing.T) { require.NoError(t, err) assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) - assert.Equal(t, "max-age=31536000", resp.Header.Get("Cache-control")) + assert.Equal(t, "", resp.Header.Get("Cache-control")) assert.Equal(t, `{ "jsonrpc": "2.0", "id": -1, @@ -142,9 +142,9 @@ func TestWriteRPCResponseHTTP(t *testing.T) { // multiple arguments w = httptest.NewRecorder() err = WriteRPCResponseHTTP(w, - false, rpctypes.NewRPCSuccessResponse(id, &sampleResult{"hello"}), - rpctypes.NewRPCSuccessResponse(id, &sampleResult{"world"})) + rpctypes.NewRPCSuccessResponse(id, &sampleResult{"world"}), + ) require.NoError(t, err) resp = w.Result() body, err = io.ReadAll(resp.Body) diff --git a/rpc/jsonrpc/server/http_uri_handler.go b/rpc/jsonrpc/server/http_uri_handler.go index d9e8b0cbb..fcdfc707a 100644 --- a/rpc/jsonrpc/server/http_uri_handler.go +++ b/rpc/jsonrpc/server/http_uri_handler.go @@ -62,7 +62,7 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit // if no error then return a success response case nil: res := rpctypes.NewRPCSuccessResponse(dummyID, result) - if wErr := WriteRPCResponseHTTP(w, rpcFunc.cache, res); wErr != nil { + if wErr := WriteRPCResponseHTTP(w, res); wErr != nil { logger.Error("failed to write response", "res", res, "err", wErr) } diff --git a/rpc/jsonrpc/server/parse_test.go b/rpc/jsonrpc/server/parse_test.go index ceb0e2020..0b8f45e6d 100644 --- a/rpc/jsonrpc/server/parse_test.go +++ b/rpc/jsonrpc/server/parse_test.go @@ -135,7 +135,7 @@ func TestParseJSONArray(t *testing.T) { func TestParseJSONRPC(t *testing.T) { demo := func(ctx context.Context, height int, name string) {} - call := NewRPCFunc(demo, "height,name", false) + call := NewRPCFunc(demo, "height,name") cases := []struct { raw string @@ -172,7 +172,7 @@ func TestParseJSONRPC(t *testing.T) { func TestParseURI(t *testing.T) { demo := func(ctx context.Context, height int, name string) {} - call := NewRPCFunc(demo, "height,name", false) + call := NewRPCFunc(demo, "height,name") cases := []struct { raw []string diff --git a/rpc/jsonrpc/server/rpc_func.go b/rpc/jsonrpc/server/rpc_func.go index 24f3c8976..17e72cb10 100644 --- a/rpc/jsonrpc/server/rpc_func.go +++ b/rpc/jsonrpc/server/rpc_func.go @@ -31,22 +31,20 @@ type RPCFunc struct { returns []reflect.Type // type of each return arg argNames []string // name of each argument ws bool // websocket only - cache bool // allow the RPC response can be cached by the proxy cache server } // NewRPCFunc wraps a function for introspection. // f is the function, args are comma separated argument names -// cache is a bool value to allow the client proxy server to cache the RPC results -func NewRPCFunc(f interface{}, args string, cache bool) *RPCFunc { - return newRPCFunc(f, args, false, cache) +func NewRPCFunc(f interface{}, args string) *RPCFunc { + return newRPCFunc(f, args, false) } // NewWSRPCFunc wraps a function for introspection and use in the websockets. func NewWSRPCFunc(f interface{}, args string) *RPCFunc { - return newRPCFunc(f, args, true, false) + return newRPCFunc(f, args, true) } -func newRPCFunc(f interface{}, args string, ws bool, c bool) *RPCFunc { +func newRPCFunc(f interface{}, args string, ws bool) *RPCFunc { var argNames []string if args != "" { argNames = strings.Split(args, ",") @@ -57,7 +55,6 @@ func newRPCFunc(f interface{}, args string, ws bool, c bool) *RPCFunc { returns: funcReturnTypes(f), argNames: argNames, ws: ws, - cache: c, } } diff --git a/rpc/jsonrpc/test/main.go b/rpc/jsonrpc/test/main.go index 524acc383..231b2bb5b 100644 --- a/rpc/jsonrpc/test/main.go +++ b/rpc/jsonrpc/test/main.go @@ -13,7 +13,7 @@ import ( ) var routes = map[string]*rpcserver.RPCFunc{ - "hello_world": rpcserver.NewRPCFunc(HelloWorld, "name,num", false), + "hello_world": rpcserver.NewRPCFunc(HelloWorld, "name,num"), } func HelloWorld(ctx context.Context, name string, num int) (Result, error) { diff --git a/test/fuzz/rpc/jsonrpc/server/handler.go b/test/fuzz/rpc/jsonrpc/server/handler.go index 61779b7f4..976174092 100644 --- a/test/fuzz/rpc/jsonrpc/server/handler.go +++ b/test/fuzz/rpc/jsonrpc/server/handler.go @@ -13,7 +13,7 @@ import ( ) var rpcFuncMap = map[string]*rs.RPCFunc{ - "c": rs.NewRPCFunc(func(s string, i int) (string, int) { return "foo", 200 }, "s,i", false), + "c": rs.NewRPCFunc(func(s string, i int) (string, int) { return "foo", 200 }, "s,i"), } var mux *http.ServeMux From 6efdba8aa90bd3137a4dd5236a9a12594255733e Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 13:38:23 -0500 Subject: [PATCH 22/27] statesync: SyncAny test buffering (#7570) --- internal/statesync/syncer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/statesync/syncer_test.go b/internal/statesync/syncer_test.go index 7ce293890..6e7b57213 100644 --- a/internal/statesync/syncer_test.go +++ b/internal/statesync/syncer_test.go @@ -68,7 +68,7 @@ func TestSyncer_SyncAny(t *testing.T) { peerAID := types.NodeID("aa") peerBID := types.NodeID("bb") peerCID := types.NodeID("cc") - rts := setup(ctx, t, connSnapshot, connQuery, stateProvider, 3) + rts := setup(ctx, t, connSnapshot, connQuery, stateProvider, 4) rts.reactor.syncer = rts.syncer From 5c1399d803fc92f5f78f9349a4a58293524b5e5c Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Wed, 12 Jan 2022 12:17:53 -0800 Subject: [PATCH 23/27] rpc: fix mock test cases (#7571) In two cases, we check for the content of an error right after asserting that no error occurs. Fix the sense of those checks. In one case, we check that there is no error with the diagnostic "expected error". It's not clear whether this means "an error was expected" (which is what I believe) or "we got the expected error". However, given the way the mock plumbing is set up, the first interpretation seems right. --- rpc/client/mock/abci_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/client/mock/abci_test.go b/rpc/client/mock/abci_test.go index 0e410d74e..18fbbf6a9 100644 --- a/rpc/client/mock/abci_test.go +++ b/rpc/client/mock/abci_test.go @@ -48,7 +48,7 @@ func TestABCIMock(t *testing.T) { // now, let's try to make some calls _, err := m.ABCIInfo(ctx) - require.NoError(t, err) + require.Error(t, err) assert.Equal(t, "foobar", err.Error()) // query always returns the response @@ -62,7 +62,7 @@ func TestABCIMock(t *testing.T) { // non-commit calls always return errors _, err = m.BroadcastTxSync(ctx, goodTx) - require.NoError(t, err) + require.Error(t, err) assert.Equal(t, "must commit", err.Error()) _, err = m.BroadcastTxAsync(ctx, goodTx) require.Error(t, err) @@ -70,7 +70,7 @@ func TestABCIMock(t *testing.T) { // commit depends on the input _, err = m.BroadcastTxCommit(ctx, badTx) - require.NoError(t, err) + require.Error(t, err) assert.Equal(t, "bad tx", err.Error()) bres, err := m.BroadcastTxCommit(ctx, goodTx) require.NoError(t, err, "%+v", err) @@ -106,7 +106,7 @@ func TestABCIRecorder(t *testing.T) { bytes.HexBytes("data"), client.ABCIQueryOptions{Prove: false}, ) - assert.NoError(t, err, "expected error on query") + assert.Error(t, err, "expected error on query") require.Equal(t, 2, len(r.Calls)) info := r.Calls[0] From e07c4cdcf23cfcf364549bdfb1f1c62c32cc22f0 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 15:32:22 -0500 Subject: [PATCH 24/27] node: collapse initialization internals (#7567) --- internal/blocksync/reactor.go | 13 +++- internal/blocksync/reactor_test.go | 4 +- internal/inspect/rpc/rpc.go | 23 ++---- internal/rpc/core/consensus.go | 4 +- internal/rpc/core/env.go | 20 ++--- internal/statesync/reactor.go | 12 +++ internal/statesync/reactor_test.go | 1 + node/node.go | 115 ++++++++++------------------- rpc/client/rpc_test.go | 5 +- 9 files changed, 87 insertions(+), 110 deletions(-) diff --git a/internal/blocksync/reactor.go b/internal/blocksync/reactor.go index a67b50874..841deb849 100644 --- a/internal/blocksync/reactor.go +++ b/internal/blocksync/reactor.go @@ -10,6 +10,7 @@ import ( "time" "github.com/tendermint/tendermint/internal/consensus" + "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/p2p" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/store" @@ -96,7 +97,8 @@ type Reactor struct { // stopping the p2p Channel(s). poolWG sync.WaitGroup - metrics *consensus.Metrics + metrics *consensus.Metrics + eventBus *eventbus.EventBus syncStartTime time.Time } @@ -113,6 +115,7 @@ func NewReactor( peerUpdates *p2p.PeerUpdates, blockSync bool, metrics *consensus.Metrics, + eventBus *eventbus.EventBus, ) (*Reactor, error) { if state.LastBlockHeight != store.Height() { @@ -146,6 +149,7 @@ func NewReactor( blockSyncOutBridgeCh: make(chan p2p.Envelope), peerUpdates: peerUpdates, metrics: metrics, + eventBus: eventBus, syncStartTime: time.Time{}, } @@ -638,6 +642,13 @@ func (r *Reactor) GetRemainingSyncTime() time.Duration { return time.Duration(int64(remain * float64(time.Second))) } +func (r *Reactor) PublishStatus(ctx context.Context, event types.EventDataBlockSyncStatus) error { + if r.eventBus == nil { + return errors.New("event bus is not configured") + } + return r.eventBus.PublishEventBlockSyncStatus(ctx, event) +} + // atomicBool is an atomic Boolean, safe for concurrent use by multiple // goroutines. type atomicBool int32 diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index db2d0bdf0..73d5a3bc7 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -181,7 +181,9 @@ func (rts *reactorTestSuite) addNode( chCreator, rts.peerUpdates[nodeID], rts.blockSync, - consensus.NopMetrics()) + consensus.NopMetrics(), + nil, // eventbus, can be nil + ) require.NoError(t, err) require.NoError(t, rts.reactors[nodeID].Start(ctx)) diff --git a/internal/inspect/rpc/rpc.go b/internal/inspect/rpc/rpc.go index 5c0d1a7e9..ad69f2c80 100644 --- a/internal/inspect/rpc/rpc.go +++ b/internal/inspect/rpc/rpc.go @@ -8,14 +8,12 @@ import ( "github.com/rs/cors" "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/internal/consensus" "github.com/tendermint/tendermint/internal/pubsub" "github.com/tendermint/tendermint/internal/rpc/core" "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/indexer" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/rpc/jsonrpc/server" - "github.com/tendermint/tendermint/types" ) // Server defines parameters for running an Inspector rpc server. @@ -33,12 +31,11 @@ type eventBusUnsubscriber interface { // Routes returns the set of routes used by the Inspector server. func Routes(cfg config.RPCConfig, s state.Store, bs state.BlockStore, es []indexer.EventSink, logger log.Logger) core.RoutesMap { env := &core.Environment{ - Config: cfg, - EventSinks: es, - StateStore: s, - BlockStore: bs, - ConsensusReactor: waitSyncCheckerImpl{}, - Logger: logger, + Config: cfg, + EventSinks: es, + StateStore: s, + BlockStore: bs, + Logger: logger, } return core.RoutesMap{ "blockchain": server.NewRPCFunc(env.BlockchainInfo, "minHeight,maxHeight"), @@ -93,16 +90,6 @@ func addCORSHandler(rpcConfig *config.RPCConfig, h http.Handler) http.Handler { return h } -type waitSyncCheckerImpl struct{} - -func (waitSyncCheckerImpl) WaitSync() bool { - return false -} - -func (waitSyncCheckerImpl) GetPeerState(peerID types.NodeID) (*consensus.PeerState, bool) { - return nil, false -} - // ListenAndServe listens on the address specified in srv.Addr and handles any // incoming requests over HTTP using the Inspector rpc handler specified on the server. func (srv *Server) ListenAndServe(ctx context.Context) error { diff --git a/internal/rpc/core/consensus.go b/internal/rpc/core/consensus.go index bc3a23ec8..6acdcc333 100644 --- a/internal/rpc/core/consensus.go +++ b/internal/rpc/core/consensus.go @@ -101,9 +101,7 @@ func (env *Environment) GetConsensusState(ctx context.Context) (*coretypes.Resul // ConsensusParams gets the consensus parameters at the given block height. // If no height is provided, it will fetch the latest consensus params. // More: https://docs.tendermint.com/master/rpc/#/Info/consensus_params -func (env *Environment) ConsensusParams( - ctx context.Context, - heightPtr *int64) (*coretypes.ResultConsensusParams, error) { +func (env *Environment) ConsensusParams(ctx context.Context, heightPtr *int64) (*coretypes.ResultConsensusParams, error) { // The latest consensus params that we know is the consensus params after the // last block. diff --git a/internal/rpc/core/env.go b/internal/rpc/core/env.go index 9adeeee71..6dfbb1478 100644 --- a/internal/rpc/core/env.go +++ b/internal/rpc/core/env.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/internal/blocksync" "github.com/tendermint/tendermint/internal/consensus" "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/mempool" @@ -52,11 +53,6 @@ type transport interface { NodeInfo() types.NodeInfo } -type consensusReactor interface { - WaitSync() bool - GetPeerState(peerID types.NodeID) (*consensus.PeerState, bool) -} - type peerManager interface { Peers() []types.NodeID Addresses(types.NodeID) []p2p.NodeAddress @@ -75,7 +71,8 @@ type Environment struct { BlockStore sm.BlockStore EvidencePool sm.EvidencePool ConsensusState consensusState - ConsensusReactor consensusReactor + ConsensusReactor *consensus.Reactor + BlockSyncReactor *blocksync.Reactor // Legacy p2p stack P2PTransport transport @@ -89,7 +86,6 @@ type Environment struct { EventSinks []indexer.EventSink EventBus *eventbus.EventBus // thread safe Mempool mempool.Mempool - BlockSyncReactor consensus.BlockSyncReactor StateSyncMetricer statesync.Metricer Logger log.Logger @@ -199,9 +195,13 @@ func (env *Environment) getHeight(latestHeight int64, heightPtr *int64) (int64, } func (env *Environment) latestUncommittedHeight() int64 { - nodeIsSyncing := env.ConsensusReactor.WaitSync() - if nodeIsSyncing { - return env.BlockStore.Height() + if env.ConsensusReactor != nil { + // consensus reactor can be nil in inspect mode. + + nodeIsSyncing := env.ConsensusReactor.WaitSync() + if nodeIsSyncing { + return env.BlockStore.Height() + } } return env.BlockStore.Height() + 1 } diff --git a/internal/statesync/reactor.go b/internal/statesync/reactor.go index 25b30d9ad..78c9d8360 100644 --- a/internal/statesync/reactor.go +++ b/internal/statesync/reactor.go @@ -13,6 +13,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/p2p" "github.com/tendermint/tendermint/internal/proxy" sm "github.com/tendermint/tendermint/internal/state" @@ -156,6 +157,7 @@ type Reactor struct { providers map[types.NodeID]*BlockProvider stateProvider StateProvider + eventBus *eventbus.EventBus metrics *Metrics backfillBlockTotal int64 backfilledBlocks int64 @@ -179,6 +181,7 @@ func NewReactor( blockStore *store.BlockStore, tempDir string, ssMetrics *Metrics, + eventBus *eventbus.EventBus, ) (*Reactor, error) { chDesc := getChannelDescriptors() @@ -219,6 +222,7 @@ func NewReactor( dispatcher: NewDispatcher(blockCh), providers: make(map[types.NodeID]*BlockProvider), metrics: ssMetrics, + eventBus: eventBus, } r.BaseService = *service.NewBaseService(logger, "StateSync", r) @@ -248,6 +252,14 @@ func (r *Reactor) OnStop() { r.dispatcher.Close() } +func (r *Reactor) PublishStatus(ctx context.Context, event types.EventDataStateSyncStatus) error { + if r.eventBus == nil { + return errors.New("event system is not configured") + } + + return r.eventBus.PublishEventStateSyncStatus(ctx, event) +} + // Sync runs a state sync, fetching snapshots and providing chunks to the // application. At the close of the operation, Sync will bootstrap the state // store and persist the commit at that height so that either consensus or diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index 4e81d53b0..92209b0be 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -178,6 +178,7 @@ func setup( rts.blockStore, "", m, + nil, // eventbus can be nil ) require.NoError(t, err) diff --git a/node/node.go b/node/node.go index 7429c07db..6d2ce40cc 100644 --- a/node/node.go +++ b/node/node.go @@ -63,23 +63,17 @@ type nodeImpl struct { isListening bool // services - eventBus *eventbus.EventBus // pub/sub for services eventSinks []indexer.EventSink stateStore sm.Store - blockStore *store.BlockStore // store the blockchain to disk - bcReactor service.Service // for block-syncing - mempoolReactor service.Service // for gossipping transactions - mempool mempool.Mempool + blockStore *store.BlockStore // store the blockchain to disk stateSync bool // whether the node should state sync on startup stateSyncReactor *statesync.Reactor // for hosting and restoring state sync snapshots - consensusReactor *consensus.Reactor // for participating in the consensus - pexReactor service.Service // for exchanging peer addresses - evidenceReactor service.Service - rpcListeners []net.Listener // rpc servers - shutdownOps closer - indexerService service.Service - rpcEnv *rpccore.Environment - prometheusSrv *http.Server + + services []service.Service + rpcListeners []net.Listener // rpc servers + shutdownOps closer + rpcEnv *rpccore.Environment + prometheusSrv *http.Server } // newDefaultNode returns a Tendermint node with default settings for the @@ -339,6 +333,7 @@ func makeNode( peerManager.Subscribe(ctx), blockSync && !stateSync, nodeMetrics.consensus, + eventBus, ) if err != nil { return nil, combineCloseError( @@ -372,6 +367,7 @@ func makeNode( blockStore, cfg.StateSync.TempDir, nodeMetrics.statesync, + eventBus, ) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) @@ -384,7 +380,6 @@ func makeNode( return nil, combineCloseError(err, makeCloser(closers)) } } - node := &nodeImpl{ config: cfg, logger: logger, @@ -396,19 +391,22 @@ func makeNode( nodeInfo: nodeInfo, nodeKey: nodeKey, + eventSinks: eventSinks, + + services: []service.Service{ + eventBus, + indexerService, + evReactor, + mpReactor, + csReactor, + bcReactor, + pexReactor, + }, + stateStore: stateStore, blockStore: blockStore, - bcReactor: bcReactor, - mempoolReactor: mpReactor, - mempool: mp, - consensusReactor: csReactor, stateSyncReactor: stateSyncReactor, stateSync: stateSync, - pexReactor: pexReactor, - evidenceReactor: evReactor, - indexerService: indexerService, - eventBus: eventBus, - eventSinks: eventSinks, shutdownOps: makeCloser(closers), @@ -494,40 +492,25 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { } n.isListening = true - if err := n.bcReactor.Start(ctx); err != nil { - return err - } + for _, reactor := range n.services { + if err := reactor.Start(ctx); err != nil { + if errors.Is(err, service.ErrAlreadyStarted) { + continue + } - if err := n.consensusReactor.Start(ctx); err != nil { - return err + return fmt.Errorf("problem starting service '%T': %w ", reactor, err) + } } if err := n.stateSyncReactor.Start(ctx); err != nil { return err } - if err := n.mempoolReactor.Start(ctx); err != nil { - return err - } - - if err := n.evidenceReactor.Start(ctx); err != nil { - return err - } - - if n.config.P2P.PexReactor { - if err := n.pexReactor.Start(ctx); err != nil { - return err - } - } - // Run state sync // TODO: We shouldn't run state sync if we already have state that has a // LastBlockHeight that is not InitialHeight if n.stateSync { - bcR, ok := n.bcReactor.(consensus.BlockSyncReactor) - if !ok { - return fmt.Errorf("this blockchain reactor does not support switching from state sync") - } + bcR := n.rpcEnv.BlockSyncReactor // we need to get the genesis state to get parameters such as state, err := sm.MakeGenesisState(n.genesisDoc) @@ -540,7 +523,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { // At the beginning of the statesync start, we use the initialHeight as the event height // because of the statesync doesn't have the concreate state height before fetched the snapshot. d := types.EventDataStateSyncStatus{Complete: false, Height: state.InitialHeight} - if err := n.eventBus.PublishEventStateSyncStatus(ctx, d); err != nil { + if err := n.stateSyncReactor.PublishStatus(ctx, d); err != nil { n.logger.Error("failed to emit the statesync start event", "err", err) } @@ -559,9 +542,9 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { return err } - n.consensusReactor.SetStateSyncingMetrics(0) + n.rpcEnv.ConsensusReactor.SetStateSyncingMetrics(0) - if err := n.eventBus.PublishEventStateSyncStatus(ctx, + if err := n.stateSyncReactor.PublishStatus(ctx, types.EventDataStateSyncStatus{ Complete: true, Height: ssState.LastBlockHeight, @@ -574,13 +557,13 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { // advancing reactors to be able to control which one of the three // is running // FIXME Very ugly to have these metrics bleed through here. - n.consensusReactor.SetBlockSyncingMetrics(1) + n.rpcEnv.ConsensusReactor.SetBlockSyncingMetrics(1) if err := bcR.SwitchToBlockSync(ctx, ssState); err != nil { n.logger.Error("failed to switch to block sync", "err", err) return err } - if err := n.eventBus.PublishEventBlockSyncStatus(ctx, + if err := bcR.PublishStatus(ctx, types.EventDataBlockSyncStatus{ Complete: false, Height: ssState.LastBlockHeight, @@ -597,25 +580,17 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { func (n *nodeImpl) OnStop() { n.logger.Info("Stopping Node") - if n.eventBus != nil { - n.eventBus.Wait() - } - if n.indexerService != nil { - n.indexerService.Wait() - } - for _, es := range n.eventSinks { if err := es.Stop(); err != nil { n.logger.Error("failed to stop event sink", "err", err) } } - n.bcReactor.Wait() - n.consensusReactor.Wait() + for _, reactor := range n.services { + reactor.Wait() + } + n.stateSyncReactor.Wait() - n.mempoolReactor.Wait() - n.evidenceReactor.Wait() - n.pexReactor.Wait() n.router.Wait() n.isListening = false @@ -693,7 +668,7 @@ func (n *nodeImpl) startRPC(ctx context.Context) ([]net.Listener, error) { wmLogger := rpcLogger.With("protocol", "websocket") wm := rpcserver.NewWebsocketManager(routes, rpcserver.OnDisconnect(func(remoteAddr string) { - err := n.eventBus.UnsubscribeAll(context.Background(), remoteAddr) + err := n.rpcEnv.EventBus.UnsubscribeAll(context.Background(), remoteAddr) if err != nil && err != tmpubsub.ErrSubscriptionNotFound { wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err) } @@ -788,19 +763,9 @@ func (n *nodeImpl) startPrometheusServer(ctx context.Context, addr string) *http return srv } -// ConsensusReactor returns the Node's ConsensusReactor. -func (n *nodeImpl) ConsensusReactor() *consensus.Reactor { - return n.consensusReactor -} - -// Mempool returns the Node's mempool. -func (n *nodeImpl) Mempool() mempool.Mempool { - return n.mempool -} - // EventBus returns the Node's EventBus. func (n *nodeImpl) EventBus() *eventbus.EventBus { - return n.eventBus + return n.rpcEnv.EventBus } // PrivValidator returns the Node's PrivValidator. diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index 03dbca7c7..cc62ffebe 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -20,6 +20,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/internal/mempool" + rpccore "github.com/tendermint/tendermint/internal/rpc/core" tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" tmmath "github.com/tendermint/tendermint/libs/math" @@ -576,10 +577,10 @@ func TestClientMethodCalls(t *testing.T) { func getMempool(t *testing.T, srv service.Service) mempool.Mempool { t.Helper() n, ok := srv.(interface { - Mempool() mempool.Mempool + RPCEnvironment() *rpccore.Environment }) require.True(t, ok) - return n.Mempool() + return n.RPCEnvironment().Mempool } // these cases are roughly the same as the TestClientMethodCalls, but From 25e665df17f2daabef089c4d75ca8bbeecdaf717 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 15:55:42 -0500 Subject: [PATCH 25/27] internal/libs: delete unused functionality (#7569) --- internal/consensus/state.go | 19 ------------- internal/libs/fail/fail.go | 40 --------------------------- internal/libs/timer/throttle_timer.go | 7 ----- internal/state/execution.go | 9 ------ 4 files changed, 75 deletions(-) delete mode 100644 internal/libs/fail/fail.go diff --git a/internal/consensus/state.go b/internal/consensus/state.go index f2f65ca52..49559f15d 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -18,7 +18,6 @@ import ( "github.com/tendermint/tendermint/crypto" cstypes "github.com/tendermint/tendermint/internal/consensus/types" "github.com/tendermint/tendermint/internal/eventbus" - "github.com/tendermint/tendermint/internal/libs/fail" sm "github.com/tendermint/tendermint/internal/state" tmevents "github.com/tendermint/tendermint/libs/events" "github.com/tendermint/tendermint/libs/log" @@ -866,14 +865,6 @@ func (cs *State) receiveRoutine(ctx context.Context, maxSteps int) { )) } - if _, ok := mi.Msg.(*VoteMessage); ok { - // we actually want to simulate failing during - // the previous WriteSync, but this isn't easy to do. - // Equivalent would be to fail here and manually remove - // some bytes from the end of the wal. - fail.Fail() // XXX - } - // handles proposals, block parts, votes cs.handleMsg(ctx, mi) @@ -1705,8 +1696,6 @@ func (cs *State) finalizeCommit(ctx context.Context, height int64) { ) logger.Debug(fmt.Sprintf("%v", block)) - fail.Fail() // XXX - // Save to blockStore. if cs.blockStore.Height() < block.Height { // NOTE: the seenCommit is local justification to commit this block, @@ -1719,8 +1708,6 @@ func (cs *State) finalizeCommit(ctx context.Context, height int64) { logger.Debug("calling finalizeCommit on already stored block", "height", block.Height) } - fail.Fail() // XXX - // Write EndHeightMessage{} for this height, implying that the blockstore // has saved the block. // @@ -1742,8 +1729,6 @@ func (cs *State) finalizeCommit(ctx context.Context, height int64) { )) } - fail.Fail() // XXX - // Create a copy of the state for staging and an event cache for txs. stateCopy := cs.state.Copy() @@ -1762,16 +1747,12 @@ func (cs *State) finalizeCommit(ctx context.Context, height int64) { return } - fail.Fail() // XXX - // must be called before we update state cs.RecordMetrics(height, block) // NewHeightStep! cs.updateToState(ctx, stateCopy) - fail.Fail() // XXX - // Private validator might have changed it's key pair => refetch pubkey. if err := cs.updatePrivValidatorPubKey(ctx); err != nil { logger.Error("failed to get private validator pubkey", "err", err) diff --git a/internal/libs/fail/fail.go b/internal/libs/fail/fail.go deleted file mode 100644 index 03a2ca668..000000000 --- a/internal/libs/fail/fail.go +++ /dev/null @@ -1,40 +0,0 @@ -package fail - -import ( - "fmt" - "os" - "strconv" -) - -func envSet() int { - callIndexToFailS := os.Getenv("FAIL_TEST_INDEX") - - if callIndexToFailS == "" { - return -1 - } - - var err error - callIndexToFail, err := strconv.Atoi(callIndexToFailS) - if err != nil { - return -1 - } - - return callIndexToFail -} - -// Fail when FAIL_TEST_INDEX == callIndex -var callIndex int // indexes Fail calls - -func Fail() { - callIndexToFail := envSet() - if callIndexToFail < 0 { - return - } - - if callIndex == callIndexToFail { - fmt.Printf("*** fail-test %d ***\n", callIndex) - os.Exit(1) - } - - callIndex++ -} diff --git a/internal/libs/timer/throttle_timer.go b/internal/libs/timer/throttle_timer.go index 76db87ee8..7bf86e80c 100644 --- a/internal/libs/timer/throttle_timer.go +++ b/internal/libs/timer/throttle_timer.go @@ -55,13 +55,6 @@ func (t *ThrottleTimer) Set() { } } -func (t *ThrottleTimer) Unset() { - t.mtx.Lock() - defer t.mtx.Unlock() - t.isSet = false - t.timer.Stop() -} - // For ease of .Stop()'ing services before .Start()'ing them, // we ignore .Stop()'s on nil ThrottleTimers func (t *ThrottleTimer) Stop() bool { diff --git a/internal/state/execution.go b/internal/state/execution.go index 71c913f2a..f80d2fa9a 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -9,7 +9,6 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/internal/eventbus" - "github.com/tendermint/tendermint/internal/libs/fail" "github.com/tendermint/tendermint/internal/mempool" "github.com/tendermint/tendermint/internal/proxy" "github.com/tendermint/tendermint/libs/log" @@ -171,15 +170,11 @@ func (blockExec *BlockExecutor) ApplyBlock( return state, ErrProxyAppConn(err) } - fail.Fail() // XXX - // Save the results before we commit. if err := blockExec.store.SaveABCIResponses(block.Height, abciResponses); err != nil { return state, err } - fail.Fail() // XXX - // validate the validator updates and convert to tendermint types abciValUpdates := abciResponses.EndBlock.ValidatorUpdates err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator) @@ -210,16 +205,12 @@ func (blockExec *BlockExecutor) ApplyBlock( // Update evpool with the latest state. blockExec.evpool.Update(state, block.Evidence.Evidence) - fail.Fail() // XXX - // Update the app hash and save the state. state.AppHash = appHash if err := blockExec.store.Save(state); err != nil { return state, err } - fail.Fail() // XXX - // Prune old heights, if requested by ABCI app. if retainHeight > 0 { pruned, err := blockExec.pruneBlocks(retainHeight) From 7a9a38d9d747f6030a81dc1e4de1e45bda87e7f3 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 16:17:43 -0500 Subject: [PATCH 26/27] service: avoid debug logs before error (#7564) --- libs/service/service.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/libs/service/service.go b/libs/service/service.go index d2594c3e0..b36aa1087 100644 --- a/libs/service/service.go +++ b/libs/service/service.go @@ -162,7 +162,6 @@ func (bs *BaseService) Start(ctx context.Context) error { return nil } - bs.logger.Debug("not starting service; already started", "service", bs.name, "impl", bs.impl.String()) return ErrAlreadyStarted } @@ -183,7 +182,6 @@ func (bs *BaseService) Stop() error { return nil } - bs.logger.Debug("not stopping service; already stopped", "service", bs.name, "impl", bs.impl.String()) return ErrAlreadyStopped } From 2a348cc1e95fb36ebb43ab569945ca22fe6708c2 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 12 Jan 2022 16:56:49 -0500 Subject: [PATCH 27/27] logging: remove reamining instances of SetLogger interface (#7572) --- abci/cmd/abci-cli/abci-cli.go | 3 +- abci/example/kvstore/kvstore_test.go | 12 +++-- abci/example/kvstore/persistent_kvstore.go | 8 +-- cmd/tendermint/commands/rollback_test.go | 5 +- internal/consensus/byzantine_test.go | 2 +- internal/consensus/common_test.go | 19 ++++--- internal/consensus/reactor_test.go | 2 +- internal/consensus/replay_test.go | 6 +-- internal/consensus/wal_generator.go | 9 ++-- internal/consensus/wal_test.go | 11 ++-- internal/inspect/rpc/rpc.go | 3 +- internal/proxy/client.go | 2 +- light/proxy/proxy.go | 4 +- node/node.go | 3 +- rpc/client/local/local.go | 9 +--- rpc/client/main_test.go | 5 +- rpc/client/rpc_test.go | 59 +++++++++++++++------- rpc/jsonrpc/client/integration_test.go | 12 ++--- rpc/jsonrpc/jsonrpc_test.go | 6 +-- rpc/jsonrpc/server/ws_handler.go | 8 +-- rpc/jsonrpc/server/ws_handler_test.go | 4 +- 21 files changed, 103 insertions(+), 89 deletions(-) diff --git a/abci/cmd/abci-cli/abci-cli.go b/abci/cmd/abci-cli/abci-cli.go index 512f4e772..acf7e6096 100644 --- a/abci/cmd/abci-cli/abci-cli.go +++ b/abci/cmd/abci-cli/abci-cli.go @@ -582,8 +582,7 @@ func cmdKVStore(cmd *cobra.Command, args []string) error { if flagPersist == "" { app = kvstore.NewApplication() } else { - app = kvstore.NewPersistentKVStoreApplication(flagPersist) - app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore")) + app = kvstore.NewPersistentKVStoreApplication(logger, flagPersist) } // Start the listener diff --git a/abci/example/kvstore/kvstore_test.go b/abci/example/kvstore/kvstore_test.go index cb402ef71..b210fecc4 100644 --- a/abci/example/kvstore/kvstore_test.go +++ b/abci/example/kvstore/kvstore_test.go @@ -76,7 +76,9 @@ func TestPersistentKVStoreKV(t *testing.T) { if err != nil { t.Fatal(err) } - kvstore := NewPersistentKVStoreApplication(dir) + logger := log.NewTestingLogger(t) + + kvstore := NewPersistentKVStoreApplication(logger, dir) key := testKey value := key tx := []byte(key) @@ -92,7 +94,9 @@ func TestPersistentKVStoreInfo(t *testing.T) { if err != nil { t.Fatal(err) } - kvstore := NewPersistentKVStoreApplication(dir) + logger := log.NewTestingLogger(t) + + kvstore := NewPersistentKVStoreApplication(logger, dir) InitKVStore(kvstore) height := int64(0) @@ -124,7 +128,9 @@ func TestValUpdates(t *testing.T) { if err != nil { t.Fatal(err) } - kvstore := NewPersistentKVStoreApplication(dir) + logger := log.NewTestingLogger(t) + + kvstore := NewPersistentKVStoreApplication(logger, dir) // init with some validators total := 10 diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index c56ad1df4..7fc32cb45 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -35,7 +35,7 @@ type PersistentKVStoreApplication struct { logger log.Logger } -func NewPersistentKVStoreApplication(dbDir string) *PersistentKVStoreApplication { +func NewPersistentKVStoreApplication(logger log.Logger, dbDir string) *PersistentKVStoreApplication { name := "kvstore" db, err := dbm.NewGoLevelDB(name, dbDir) if err != nil { @@ -47,7 +47,7 @@ func NewPersistentKVStoreApplication(dbDir string) *PersistentKVStoreApplication return &PersistentKVStoreApplication{ app: &Application{state: state}, valAddrToPubKeyMap: make(map[string]cryptoproto.PublicKey), - logger: log.NewNopLogger(), + logger: logger, } } @@ -55,10 +55,6 @@ func (app *PersistentKVStoreApplication) Close() error { return app.app.state.db.Close() } -func (app *PersistentKVStoreApplication) SetLogger(l log.Logger) { - app.logger = l -} - func (app *PersistentKVStoreApplication) Info(req types.RequestInfo) types.ResponseInfo { res := app.app.Info(req) res.LastBlockHeight = app.app.state.Height diff --git a/cmd/tendermint/commands/rollback_test.go b/cmd/tendermint/commands/rollback_test.go index f842ddd0e..167fbc1f3 100644 --- a/cmd/tendermint/commands/rollback_test.go +++ b/cmd/tendermint/commands/rollback_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/cmd/tendermint/commands" + "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/rpc/client/local" rpctest "github.com/tendermint/tendermint/rpc/test" e2e "github.com/tendermint/tendermint/test/e2e/app" @@ -49,7 +50,9 @@ func TestRollbackIntegration(t *testing.T) { node2, _, err2 := rpctest.StartTendermint(ctx, cfg, app, rpctest.SuppressStdout) require.NoError(t, err2) - client, err := local.New(node2.(local.NodeService)) + logger := log.NewTestingLogger(t) + + client, err := local.New(logger, node2.(local.NodeService)) require.NoError(t, err) ticker := time.NewTicker(200 * time.Millisecond) diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index 742beecee..c118ac713 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -59,7 +59,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { defer os.RemoveAll(thisConfig.RootDir) ensureDir(t, path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal - app := appFunc(t) + app := appFunc(t, logger) vals := types.TM2PB.ValidatorUpdates(state.Validators) app.InitChain(abci.RequestInitChain{Validators: vals}) diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index 523e596d2..1e1a20198 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "os" - "path" "path/filepath" "sort" "sync" @@ -737,7 +736,7 @@ func randConsensusState( nValidators int, testName string, tickerFunc func() TimeoutTicker, - appFunc func(t *testing.T) abci.Application, + appFunc func(t *testing.T, logger log.Logger) abci.Application, configOpts ...func(*config.Config), ) ([]*State, cleanupFunc) { @@ -764,7 +763,7 @@ func randConsensusState( ensureDir(t, filepath.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal - app := appFunc(t) + app := appFunc(t, logger) if appCloser, ok := app.(io.Closer); ok { closeFuncs = append(closeFuncs, appCloser.Close) @@ -797,7 +796,7 @@ func randConsensusNetWithPeers( nPeers int, testName string, tickerFunc func() TimeoutTicker, - appFunc func(string) abci.Application, + appFunc func(log.Logger, string) abci.Application, ) ([]*State, *types.GenesisDoc, *config.Config, cleanupFunc) { t.Helper() @@ -831,7 +830,7 @@ func randConsensusNetWithPeers( require.NoError(t, err) } - app := appFunc(path.Join(cfg.DBDir(), fmt.Sprintf("%s_%d", testName, i))) + app := appFunc(logger, filepath.Join(cfg.DBDir(), fmt.Sprintf("%s_%d", testName, i))) vals := types.TM2PB.ValidatorUpdates(state.Validators) if _, ok := app.(*kvstore.PersistentKVStoreApplication); ok { // simulate handshake, receive app version. If don't do this, replay test will fail @@ -912,21 +911,21 @@ func (m *mockTicker) Chan() <-chan timeoutInfo { func (*mockTicker) SetLogger(log.Logger) {} -func newPersistentKVStore(t *testing.T) abci.Application { +func newPersistentKVStore(t *testing.T, logger log.Logger) abci.Application { t.Helper() dir, err := os.MkdirTemp("", "persistent-kvstore") require.NoError(t, err) - return kvstore.NewPersistentKVStoreApplication(dir) + return kvstore.NewPersistentKVStoreApplication(logger, dir) } -func newKVStore(_ *testing.T) abci.Application { +func newKVStore(_ *testing.T, _ log.Logger) abci.Application { return kvstore.NewApplication() } -func newPersistentKVStoreWithPath(dbDir string) abci.Application { - return kvstore.NewPersistentKVStoreApplication(dbDir) +func newPersistentKVStoreWithPath(logger log.Logger, dbDir string) abci.Application { + return kvstore.NewPersistentKVStoreApplication(logger, dbDir) } func signDataIsEqual(v1 *types.Vote, v2 *tmproto.Vote) bool { diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index 19f45f674..45da5b7eb 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -398,7 +398,7 @@ func TestReactorWithEvidence(t *testing.T) { defer os.RemoveAll(thisConfig.RootDir) ensureDir(t, path.Dir(thisConfig.Consensus.WalFile()), 0700) // dir for wal - app := appFunc(t) + app := appFunc(t, logger) vals := types.TM2PB.ValidatorUpdates(state.Validators) app.InitChain(abci.RequestInitChain{Validators: vals}) diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index dc05cc226..898545ccf 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -763,7 +763,7 @@ func testHandshakeReplay( testConfig, err := ResetConfig(fmt.Sprintf("%s_%v_s", t.Name(), mode)) require.NoError(t, err) defer func() { _ = os.RemoveAll(testConfig.RootDir) }() - walBody, err := WALWithNBlocks(ctx, t, numBlocks) + walBody, err := WALWithNBlocks(ctx, t, logger, numBlocks) require.NoError(t, err) walFile := tempWALWithData(t, walBody) cfg.Consensus.SetWalFile(walFile) @@ -805,7 +805,7 @@ func testHandshakeReplay( latestAppHash := state.AppHash // make a new client creator - kvstoreApp := kvstore.NewPersistentKVStoreApplication( + kvstoreApp := kvstore.NewPersistentKVStoreApplication(logger, filepath.Join(cfg.DBDir(), fmt.Sprintf("replay_test_%d_%d_a_r%d", nBlocks, mode, rand.Int()))) t.Cleanup(func() { require.NoError(t, kvstoreApp.Close()) }) @@ -959,7 +959,7 @@ func buildTMStateFromChain( t.Helper() // run the whole chain against this client to build up the tendermint state - kvstoreApp := kvstore.NewPersistentKVStoreApplication( + kvstoreApp := kvstore.NewPersistentKVStoreApplication(logger, filepath.Join(cfg.DBDir(), fmt.Sprintf("replay_test_%d_%d_t", nBlocks, mode))) defer kvstoreApp.Close() clientCreator := abciclient.NewLocalCreator(kvstoreApp) diff --git a/internal/consensus/wal_generator.go b/internal/consensus/wal_generator.go index 5012da5b1..19d447222 100644 --- a/internal/consensus/wal_generator.go +++ b/internal/consensus/wal_generator.go @@ -31,13 +31,12 @@ import ( // persistent kvstore application and special consensus wal instance // (byteBufferWAL) and waits until numBlocks are created. // If the node fails to produce given numBlocks, it returns an error. -func WALGenerateNBlocks(ctx context.Context, t *testing.T, wr io.Writer, numBlocks int) (err error) { +func WALGenerateNBlocks(ctx context.Context, t *testing.T, logger log.Logger, wr io.Writer, numBlocks int) (err error) { cfg := getConfig(t) - app := kvstore.NewPersistentKVStoreApplication(filepath.Join(cfg.DBDir(), "wal_generator")) + app := kvstore.NewPersistentKVStoreApplication(logger, filepath.Join(cfg.DBDir(), "wal_generator")) t.Cleanup(func() { require.NoError(t, app.Close()) }) - logger := log.TestingLogger().With("wal_generator", "wal_generator") logger.Info("generating WAL (last height msg excluded)", "numBlocks", numBlocks) // COPY PASTE FROM node.go WITH A FEW MODIFICATIONS @@ -116,11 +115,11 @@ func WALGenerateNBlocks(ctx context.Context, t *testing.T, wr io.Writer, numBloc } // WALWithNBlocks returns a WAL content with numBlocks. -func WALWithNBlocks(ctx context.Context, t *testing.T, numBlocks int) (data []byte, err error) { +func WALWithNBlocks(ctx context.Context, t *testing.T, logger log.Logger, numBlocks int) (data []byte, err error) { var b bytes.Buffer wr := bufio.NewWriter(&b) - if err := WALGenerateNBlocks(ctx, t, wr, numBlocks); err != nil { + if err := WALGenerateNBlocks(ctx, t, logger, wr, numBlocks); err != nil { return []byte{}, err } diff --git a/internal/consensus/wal_test.go b/internal/consensus/wal_test.go index a0731e8cf..a9d717371 100644 --- a/internal/consensus/wal_test.go +++ b/internal/consensus/wal_test.go @@ -45,7 +45,7 @@ func TestWALTruncate(t *testing.T) { // 60 block's size nearly 70K, greater than group's headBuf size(4096 * 10), // when headBuf is full, truncate content will Flush to the file. at this // time, RotateFile is called, truncate content exist in each file. - err = WALGenerateNBlocks(ctx, t, wal.Group(), 60) + err = WALGenerateNBlocks(ctx, t, logger, wal.Group(), 60) require.NoError(t, err) time.Sleep(1 * time.Millisecond) // wait groupCheckDuration, make sure RotateFile run @@ -136,13 +136,15 @@ func TestWALSearchForEndHeight(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - walBody, err := WALWithNBlocks(ctx, t, 6) + logger := log.NewTestingLogger(t) + + walBody, err := WALWithNBlocks(ctx, t, logger, 6) if err != nil { t.Fatal(err) } walFile := tempWALWithData(t, walBody) - wal, err := NewWAL(log.TestingLogger(), walFile) + wal, err := NewWAL(logger, walFile) require.NoError(t, err) h := int64(3) @@ -171,9 +173,10 @@ func TestWALPeriodicSync(t *testing.T) { require.NoError(t, err) wal.SetFlushInterval(walTestFlushInterval) + logger := log.NewTestingLogger(t) // Generate some data - err = WALGenerateNBlocks(ctx, t, wal.Group(), 5) + err = WALGenerateNBlocks(ctx, t, logger, wal.Group(), 5) require.NoError(t, err) // We should have data in the buffer now diff --git a/internal/inspect/rpc/rpc.go b/internal/inspect/rpc/rpc.go index ad69f2c80..968937fea 100644 --- a/internal/inspect/rpc/rpc.go +++ b/internal/inspect/rpc/rpc.go @@ -66,10 +66,9 @@ func Handler(rpcConfig *config.RPCConfig, routes core.RoutesMap, logger log.Logg wmLogger.Error("Failed to unsubscribe addr from events", "addr", remoteAddr, "err", err) } } - wm := server.NewWebsocketManager(routes, + wm := server.NewWebsocketManager(logger, routes, server.OnDisconnect(websocketDisconnectFn), server.ReadLimit(rpcConfig.MaxBodyBytes)) - wm.SetLogger(wmLogger) mux.HandleFunc("/websocket", wm.WebsocketHandler) server.RegisterRPCFuncs(mux, routes, logger) diff --git a/internal/proxy/client.go b/internal/proxy/client.go index 4e034802e..d01634bdf 100644 --- a/internal/proxy/client.go +++ b/internal/proxy/client.go @@ -21,7 +21,7 @@ func DefaultClientCreator(logger log.Logger, addr, transport, dbDir string) (abc case "kvstore": return abciclient.NewLocalCreator(kvstore.NewApplication()), noopCloser{} case "persistent_kvstore": - app := kvstore.NewPersistentKVStoreApplication(dbDir) + app := kvstore.NewPersistentKVStoreApplication(logger, dbDir) return abciclient.NewLocalCreator(app), app case "e2e": app, err := e2e.NewApplication(e2e.DefaultConfig(dbDir)) diff --git a/light/proxy/proxy.go b/light/proxy/proxy.go index 444eefb88..c7f6c4821 100644 --- a/light/proxy/proxy.go +++ b/light/proxy/proxy.go @@ -95,7 +95,7 @@ func (p *Proxy) listen(ctx context.Context) (net.Listener, *http.ServeMux, error // 2) Allow websocket connections. wmLogger := p.Logger.With("protocol", "websocket") - wm := rpcserver.NewWebsocketManager(r, + wm := rpcserver.NewWebsocketManager(wmLogger, r, rpcserver.OnDisconnect(func(remoteAddr string) { err := p.Client.UnsubscribeAll(context.Background(), remoteAddr) if err != nil && err != tmpubsub.ErrSubscriptionNotFound { @@ -104,7 +104,7 @@ func (p *Proxy) listen(ctx context.Context) (net.Listener, *http.ServeMux, error }), rpcserver.ReadLimit(p.Config.MaxBodyBytes), ) - wm.SetLogger(wmLogger) + mux.HandleFunc("/websocket", wm.WebsocketHandler) // 3) Start a client. diff --git a/node/node.go b/node/node.go index 6d2ce40cc..a6ce80012 100644 --- a/node/node.go +++ b/node/node.go @@ -666,7 +666,7 @@ func (n *nodeImpl) startRPC(ctx context.Context) ([]net.Listener, error) { mux := http.NewServeMux() rpcLogger := n.logger.With("module", "rpc-server") wmLogger := rpcLogger.With("protocol", "websocket") - wm := rpcserver.NewWebsocketManager(routes, + wm := rpcserver.NewWebsocketManager(wmLogger, routes, rpcserver.OnDisconnect(func(remoteAddr string) { err := n.rpcEnv.EventBus.UnsubscribeAll(context.Background(), remoteAddr) if err != nil && err != tmpubsub.ErrSubscriptionNotFound { @@ -675,7 +675,6 @@ func (n *nodeImpl) startRPC(ctx context.Context) ([]net.Listener, error) { }), rpcserver.ReadLimit(cfg.MaxBodyBytes), ) - wm.SetLogger(wmLogger) mux.HandleFunc("/websocket", wm.WebsocketHandler) rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger) listener, err := rpcserver.Listen( diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index 69cbb3ebd..7f2ab46d4 100644 --- a/rpc/client/local/local.go +++ b/rpc/client/local/local.go @@ -51,25 +51,20 @@ type NodeService interface { } // New configures a client that calls the Node directly. -func New(node NodeService) (*Local, error) { +func New(logger log.Logger, node NodeService) (*Local, error) { env := node.RPCEnvironment() if env == nil { return nil, errors.New("rpc is nil") } return &Local{ EventBus: node.EventBus(), - Logger: log.NewNopLogger(), + Logger: logger, env: env, }, nil } var _ rpcclient.Client = (*Local)(nil) -// SetLogger allows to set a logger on the client. -func (c *Local) SetLogger(l log.Logger) { - c.Logger = l -} - func (c *Local) Status(ctx context.Context) (*coretypes.ResultStatus, error) { return c.env.Status(ctx) } diff --git a/rpc/client/main_test.go b/rpc/client/main_test.go index 5ae9b951c..ad3043098 100644 --- a/rpc/client/main_test.go +++ b/rpc/client/main_test.go @@ -10,11 +10,12 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/example/kvstore" "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/service" rpctest "github.com/tendermint/tendermint/rpc/test" ) -func NodeSuite(t *testing.T) (service.Service, *config.Config) { +func NodeSuite(t *testing.T, logger log.Logger) (service.Service, *config.Config) { t.Helper() ctx, cancel := context.WithCancel(context.Background()) @@ -26,7 +27,7 @@ func NodeSuite(t *testing.T) (service.Service, *config.Config) { dir, err := os.MkdirTemp("/tmp", fmt.Sprint("rpc-client-test-", t.Name())) require.NoError(t, err) - app := kvstore.NewPersistentKVStoreApplication(dir) + app := kvstore.NewPersistentKVStoreApplication(logger, dir) node, closer, err := rpctest.StartTendermint(ctx, conf, app, rpctest.SuppressStdout) require.NoError(t, err) diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index cc62ffebe..37cc9707b 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -34,14 +34,14 @@ import ( "github.com/tendermint/tendermint/types" ) -func getHTTPClient(t *testing.T, conf *config.Config) *rpchttp.HTTP { +func getHTTPClient(t *testing.T, logger log.Logger, conf *config.Config) *rpchttp.HTTP { t.Helper() rpcAddr := conf.RPC.ListenAddress c, err := rpchttp.NewWithClient(rpcAddr, http.DefaultClient) require.NoError(t, err) - c.Logger = log.NewTestingLogger(t) + c.Logger = logger t.Cleanup(func() { if c.IsRunning() { require.NoError(t, c.Stop()) @@ -51,7 +51,7 @@ func getHTTPClient(t *testing.T, conf *config.Config) *rpchttp.HTTP { return c } -func getHTTPClientWithTimeout(t *testing.T, conf *config.Config, timeout time.Duration) *rpchttp.HTTP { +func getHTTPClientWithTimeout(t *testing.T, logger log.Logger, conf *config.Config, timeout time.Duration) *rpchttp.HTTP { t.Helper() rpcAddr := conf.RPC.ListenAddress @@ -60,7 +60,7 @@ func getHTTPClientWithTimeout(t *testing.T, conf *config.Config, timeout time.Du c, err := rpchttp.NewWithClient(rpcAddr, http.DefaultClient) require.NoError(t, err) - c.Logger = log.NewTestingLogger(t) + c.Logger = logger t.Cleanup(func() { http.DefaultClient.Timeout = 0 if c.IsRunning() { @@ -78,12 +78,13 @@ func GetClients(t *testing.T, ns service.Service, conf *config.Config) []client. node, ok := ns.(rpclocal.NodeService) require.True(t, ok) - ncl, err := rpclocal.New(node) + logger := log.NewTestingLogger(t) + ncl, err := rpclocal.New(logger, node) require.NoError(t, err) return []client.Client{ ncl, - getHTTPClient(t, conf), + getHTTPClient(t, logger, conf), } } @@ -91,7 +92,9 @@ func TestClientOperations(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - _, conf := NodeSuite(t) + logger := log.NewTestingLogger(t) + + _, conf := NodeSuite(t, logger) t.Run("NilCustomHTTPClient", func(t *testing.T) { _, err := rpchttp.NewWithClient("http://example.com", nil) @@ -129,14 +132,16 @@ func TestClientOperations(t *testing.T) { }) t.Run("Batching", func(t *testing.T) { t.Run("JSONRPCCalls", func(t *testing.T) { - c := getHTTPClient(t, conf) + logger := log.NewTestingLogger(t) + c := getHTTPClient(t, logger, conf) testBatchedJSONRPCCalls(ctx, t, c) }) t.Run("JSONRPCCallsCancellation", func(t *testing.T) { _, _, tx1 := MakeTxKV() _, _, tx2 := MakeTxKV() - c := getHTTPClient(t, conf) + logger := log.NewTestingLogger(t) + c := getHTTPClient(t, logger, conf) batch := c.NewBatch() _, err := batch.BroadcastTxCommit(ctx, tx1) require.NoError(t, err) @@ -150,19 +155,25 @@ func TestClientOperations(t *testing.T) { require.Equal(t, 0, batch.Count()) }) t.Run("SendingEmptyRequest", func(t *testing.T) { - c := getHTTPClient(t, conf) + logger := log.NewTestingLogger(t) + + c := getHTTPClient(t, logger, conf) batch := c.NewBatch() _, err := batch.Send(ctx) require.Error(t, err, "sending an empty batch of JSON RPC requests should result in an error") }) t.Run("ClearingEmptyRequest", func(t *testing.T) { - c := getHTTPClient(t, conf) + logger := log.NewTestingLogger(t) + + c := getHTTPClient(t, logger, conf) batch := c.NewBatch() require.Zero(t, batch.Clear(), "clearing an empty batch of JSON RPC requests should result in a 0 result") }) t.Run("ConcurrentJSONRPC", func(t *testing.T) { + logger := log.NewTestingLogger(t) + var wg sync.WaitGroup - c := getHTTPClient(t, conf) + c := getHTTPClient(t, logger, conf) for i := 0; i < 50; i++ { wg.Add(1) go func() { @@ -174,7 +185,9 @@ func TestClientOperations(t *testing.T) { }) }) t.Run("HTTPReturnsErrorIfClientIsNotRunning", func(t *testing.T) { - c := getHTTPClientWithTimeout(t, conf, 100*time.Millisecond) + logger := log.NewTestingLogger(t) + + c := getHTTPClientWithTimeout(t, logger, conf, 100*time.Millisecond) // on Subscribe _, err := c.Subscribe(ctx, "TestHeaderEvents", @@ -196,7 +209,9 @@ func TestClientOperations(t *testing.T) { func TestClientMethodCalls(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, conf := NodeSuite(t) + logger := log.NewTestingLogger(t) + + n, conf := NodeSuite(t, logger) // for broadcast tx tests pool := getMempool(t, n) @@ -591,7 +606,9 @@ func TestClientMethodCallsAdvanced(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - n, conf := NodeSuite(t) + logger := log.NewTestingLogger(t) + + n, conf := NodeSuite(t, logger) pool := getMempool(t, n) t.Run("UnconfirmedTxs", func(t *testing.T) { @@ -654,7 +671,9 @@ func TestClientMethodCallsAdvanced(t *testing.T) { pool.Flush() }) t.Run("Tx", func(t *testing.T) { - c := getHTTPClient(t, conf) + logger := log.NewTestingLogger(t) + + c := getHTTPClient(t, logger, conf) // first we broadcast a tx _, _, tx := MakeTxKV() @@ -710,7 +729,9 @@ func TestClientMethodCallsAdvanced(t *testing.T) { } }) t.Run("TxSearchWithTimeout", func(t *testing.T) { - timeoutClient := getHTTPClientWithTimeout(t, conf, 10*time.Second) + logger := log.NewTestingLogger(t) + + timeoutClient := getHTTPClientWithTimeout(t, logger, conf, 10*time.Second) _, _, tx := MakeTxKV() _, err := timeoutClient.BroadcastTxCommit(ctx, tx) @@ -723,7 +744,9 @@ func TestClientMethodCallsAdvanced(t *testing.T) { }) t.Run("TxSearch", func(t *testing.T) { t.Skip("Test Asserts Non-Deterministic Results") - c := getHTTPClient(t, conf) + logger := log.NewTestingLogger(t) + + c := getHTTPClient(t, logger, conf) // first we broadcast a few txs for i := 0; i < 10; i++ { diff --git a/rpc/jsonrpc/client/integration_test.go b/rpc/jsonrpc/client/integration_test.go index a8353aced..961b9a619 100644 --- a/rpc/jsonrpc/client/integration_test.go +++ b/rpc/jsonrpc/client/integration_test.go @@ -8,6 +8,7 @@ package client import ( "bytes" + "context" "errors" "net" "regexp" @@ -15,34 +16,33 @@ import ( "time" "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/libs/log" ) func TestWSClientReconnectWithJitter(t *testing.T) { n := 8 - maxReconnectAttempts := 3 + var maxReconnectAttempts uint = 3 // Max wait time is ceil(1+0.999) + ceil(2+0.999) + ceil(4+0.999) + ceil(...) = 2 + 3 + 5 = 10s + ... maxSleepTime := time.Second * time.Duration(((1<