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 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/abci/cmd/abci-cli/abci-cli.go b/abci/cmd/abci-cli/abci-cli.go index 783c41dbb..acf7e6096 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,15 +575,14 @@ 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 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/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) } diff --git a/cmd/priv_val_server/main.go b/cmd/priv_val_server/main.go index 0708edd5c..bdd5091d9 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() @@ -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/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/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/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/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 } 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= diff --git a/internal/blocksync/reactor.go b/internal/blocksync/reactor.go index b3142d953..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{}, } @@ -354,7 +358,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) @@ -639,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 245f2753e..73d5a3bc7 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, @@ -182,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)) @@ -206,7 +207,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 +246,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 +274,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 +326,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 +360,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..c118ac713 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++ { @@ -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}) @@ -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/common_test.go b/internal/consensus/common_test.go index b3507184d..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,11 +736,11 @@ 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) { - 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() @@ -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,11 +796,11 @@ 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() - 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() @@ -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 @@ -859,7 +858,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 @@ -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/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/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/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/reactor_test.go b/internal/consensus/reactor_test.go index a717c4b8b..45da5b7eb 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() @@ -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 c7f1140a8..898545ccf 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 @@ -764,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) @@ -806,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()) }) @@ -960,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) @@ -1023,8 +1022,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 +1285,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/state.go b/internal/consensus/state.go index 1ae196b23..2809b48d2 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" @@ -18,10 +19,8 @@ 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" - 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" @@ -254,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. @@ -867,14 +866,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) @@ -1708,8 +1699,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, @@ -1722,8 +1711,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. // @@ -1745,8 +1732,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() @@ -1765,16 +1750,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/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/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/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/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/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/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/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/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/inspect/rpc/rpc.go b/internal/inspect/rpc/rpc.go index 7ed47962a..968937fea 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,24 +31,23 @@ 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", 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"), } } @@ -69,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) @@ -93,16 +89,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/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/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/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/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/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/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..6acdcc333 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 @@ -100,9 +101,7 @@ func (env *Environment) GetConsensusState(ctx *rpctypes.Context) (*coretypes.Res // 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 *rpctypes.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/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/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/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/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/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/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) 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.go b/internal/statesync/reactor.go index b9113cc21..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 @@ -887,7 +899,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/statesync/reactor_test.go b/internal/statesync/reactor_test.go index a53cd3a68..92209b0be 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, @@ -176,12 +178,13 @@ func setup( rts.blockStore, "", m, + nil, // eventbus can be nil ) require.NoError(t, err) rts.syncer = newSyncer( *cfg, - log.NewNopLogger(), + logger.With("component", "syncer"), conn, connQuery, stateProvider, @@ -191,13 +194,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 } @@ -233,7 +237,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 +438,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 +733,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 +802,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 +815,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 +842,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 +852,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/statesync/syncer_test.go b/internal/statesync/syncer_test.go index 3126a7688..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 @@ -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) 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/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/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 } 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/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/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/light/proxy/routes.go b/light/proxy/routes.go index ac2e8b5df..6f5b3c1db 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" ) @@ -18,149 +19,149 @@ 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"), } } -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/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.go b/node/node.go index daf256104..a6ce80012 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), @@ -442,76 +440,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 := &nodeImpl{ - 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 Node. It implements service.Service. func (n *nodeImpl) OnStart(ctx context.Context) error { if n.config.RPC.PprofListenAddress != "" { @@ -546,7 +474,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,46 +492,25 @@ 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 - } + for _, reactor := range n.services { + if err := reactor.Start(ctx); err != nil { + if errors.Is(err, service.ErrAlreadyStarted) { + continue + } - // Start the real consensus reactor separately since the switch uses the shim. - 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 - } - - // Start the real mempool reactor separately since the switch uses the shim. - 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 + return fmt.Errorf("problem starting service '%T': %w ", reactor, err) } } - if n.config.P2P.PexReactor { - if err := n.pexReactor.Start(ctx); err != nil { - return err - } + if err := n.stateSyncReactor.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) @@ -616,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) } @@ -635,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, @@ -650,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, @@ -673,27 +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) } } - if n.config.Mode != config.ModeSeed { - n.bcReactor.Wait() - n.consensusReactor.Wait() - n.stateSyncReactor.Wait() - n.mempoolReactor.Wait() - n.evidenceReactor.Wait() + for _, reactor := range n.services { + reactor.Wait() } - n.pexReactor.Wait() + + n.stateSyncReactor.Wait() n.router.Wait() n.isListening = false @@ -769,16 +666,15 @@ 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.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) } }), rpcserver.ReadLimit(cfg.MaxBodyBytes), ) - wm.SetLogger(wmLogger) mux.HandleFunc("/websocket", wm.WebsocketHandler) rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger) listener, err := rpcserver.Listen( @@ -866,19 +762,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/node/node_test.go b/node/node_test.go index 2a32f5957..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) @@ -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/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) + } + } +} 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/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..2867d7be5 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) } } @@ -298,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_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..cf5567561 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: @@ -144,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 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) diff --git a/rpc/client/http/http.go b/rpc/client/http/http.go index d18671fd0..7dd6abb76 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", nil, 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", nil, result); err != nil { return nil, err } - return result, nil } @@ -235,13 +231,14 @@ func (c *baseRPCClient) ABCIQueryWithOptions( data bytes.HexBytes, opts rpcclient.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) { result := new(coretypes.ResultABCIQuery) - _, err := c.caller.Call(ctx, "abci_query", - map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove}, - result) - if 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 } @@ -250,8 +247,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", txArgs{Tx: tx}, result); err != nil { return nil, err } return result, nil @@ -277,8 +273,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, txArgs{Tx: tx}, result); err != nil { return nil, err } return result, nil @@ -289,12 +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 - } - _, err := c.caller.Call(ctx, "unconfirmed_txs", params, result) - if err != nil { + + if err := c.caller.Call(ctx, "unconfirmed_txs", unconfirmedArgs{Limit: limit}, 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", nil, 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", txArgs{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", txKeyArgs{TxKey: 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", nil, 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", nil, 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", nil, result); err != nil { return nil, err } return result, nil @@ -358,12 +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 - } - _, err := c.caller.Call(ctx, "consensus_params", params, result) - if err != nil { + if err := c.caller.Call(ctx, "consensus_params", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -371,8 +351,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", nil, result); err != nil { return nil, err } return result, nil @@ -384,10 +363,10 @@ func (c *baseRPCClient) BlockchainInfo( maxHeight int64, ) (*coretypes.ResultBlockchainInfo, error) { result := new(coretypes.ResultBlockchainInfo) - _, err := c.caller.Call(ctx, "blockchain", - map[string]interface{}{"minHeight": minHeight, "maxHeight": maxHeight}, - result) - if err != nil { + if err := c.caller.Call(ctx, "blockchain", blockchainInfoArgs{ + MinHeight: minHeight, + MaxHeight: maxHeight, + }, result); err != nil { return nil, err } return result, nil @@ -395,8 +374,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", nil, result); err != nil { return nil, err } return result, nil @@ -404,8 +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) - _, err := c.caller.Call(ctx, "genesis_chunked", map[string]interface{}{"chunk": id}, result) - if err != nil { + if err := c.caller.Call(ctx, "genesis_chunked", genesisChunkArgs{Chunk: id}, result); err != nil { return nil, err } return result, nil @@ -413,12 +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 - } - _, err := c.caller.Call(ctx, "block", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -426,11 +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, - } - _, err := c.caller.Call(ctx, "block_by_hash", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block_by_hash", hashArgs{Hash: hash}, result); err != nil { return nil, err } return result, nil @@ -441,12 +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 - } - _, err := c.caller.Call(ctx, "block_results", params, result) - if err != nil { + if err := c.caller.Call(ctx, "block_results", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -454,12 +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 - } - _, err := c.caller.Call(ctx, "header", params, result) - if err != nil { + if err := c.caller.Call(ctx, "header", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -467,11 +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, - } - _, err := c.caller.Call(ctx, "header_by_hash", params, result) - if err != nil { + if err := c.caller.Call(ctx, "header_by_hash", hashArgs{Hash: hash}, result); err != nil { return nil, err } return result, nil @@ -479,12 +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 - } - _, err := c.caller.Call(ctx, "commit", params, result) - if err != nil { + if err := c.caller.Call(ctx, "commit", heightArgs{Height: height}, result); err != nil { return nil, err } return result, nil @@ -492,12 +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, - } - _, err := c.caller.Call(ctx, "tx", params, result) - if err != nil { + if err := c.caller.Call(ctx, "tx", hashArgs{Hash: hash, Prove: prove}, result); err != nil { return nil, err } return result, nil @@ -511,23 +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 - } - - _, err := c.caller.Call(ctx, "tx_search", params, result) - if 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 } @@ -540,22 +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 - } - - _, err := c.caller.Call(ctx, "block_search", params, result) - if 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 } @@ -569,18 +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 - } - _, err := c.caller.Call(ctx, "validators", params, result) - if 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 @@ -591,8 +510,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/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"` +} diff --git a/rpc/client/local/local.go b/rpc/client/local/local.go index 4a833af9c..7f2ab46d4 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 } @@ -53,32 +51,26 @@ 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(), - ctx: &rpctypes.Context{}, + 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(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 +82,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 +114,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/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/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] 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/client/rpc_test.go b/rpc/client/rpc_test.go index 03dbca7c7..37cc9707b 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" @@ -33,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()) @@ -50,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 @@ -59,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() { @@ -77,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), } } @@ -90,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) @@ -128,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) @@ -149,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() { @@ -173,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", @@ -195,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) @@ -576,10 +592,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 @@ -590,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) { @@ -653,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() @@ -709,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) @@ -722,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/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 45f516f04..b2823d5e7 100644 --- a/rpc/jsonrpc/client/http_json_client.go +++ b/rpc/jsonrpc/client/http_json_client.go @@ -106,15 +106,15 @@ 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. +// 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 } //------------------------------------------------------------- @@ -134,8 +134,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) @@ -182,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") @@ -214,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) @@ -348,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/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< 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)) 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 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))) + continue } 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)) 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)) // 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)) } } - - if c && !rpcFunc.cache { - c = false - } } if len(responses) > 0 { - if wErr := WriteRPCResponseHTTP(w, c, responses...); wErr != nil { + if wErr := WriteRPCResponseHTTP(w, responses...); wErr != nil { logger.Error("failed to write responses", "err", wErr) } } @@ -160,6 +119,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,11 +186,29 @@ 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) { + 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 + } + 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. // // 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 @@ -276,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 1a65d414d..92ad1435c 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"), + "block": NewRPCFunc(func(ctx context.Context, h int) (string, error) { return "block", nil }, "height"), } mux := http.NewServeMux() logger := log.NewNopLogger() @@ -237,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 9fb5c1cde..fcdfc707a 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) @@ -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 6e7464739..0b8f45e6d 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,8 +134,8 @@ func TestParseJSONArray(t *testing.T) { } func TestParseJSONRPC(t *testing.T) { - demo := func(ctx *rpctypes.Context, height int, name string) {} - call := NewRPCFunc(demo, "height,name", false) + demo := func(ctx context.Context, height int, name string) {} + call := NewRPCFunc(demo, "height,name") cases := []struct { raw string @@ -171,8 +171,8 @@ func TestParseJSONRPC(t *testing.T) { } func TestParseURI(t *testing.T) { - demo := func(ctx *rpctypes.Context, height int, name string) {} - call := NewRPCFunc(demo, "height,name", false) + demo := func(ctx context.Context, height int, name string) {} + 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/server/ws_handler.go b/rpc/jsonrpc/server/ws_handler.go index cfba6d13a..845180d62 100644 --- a/rpc/jsonrpc/server/ws_handler.go +++ b/rpc/jsonrpc/server/ws_handler.go @@ -41,6 +41,7 @@ type WebsocketManager struct { // NewWebsocketManager returns a new WebsocketManager that passes a map of // functions, connection options and logger to new WS connections. func NewWebsocketManager( + logger log.Logger, funcMap map[string]*RPCFunc, wsConnOptions ...func(*wsConnection), ) *WebsocketManager { @@ -60,16 +61,11 @@ func NewWebsocketManager( return true }, }, - logger: log.NewNopLogger(), + logger: logger, wsConnOptions: wsConnOptions, } } -// SetLogger sets the logger. -func (wm *WebsocketManager) SetLogger(l log.Logger) { - wm.logger = l -} - // WebsocketHandler upgrades the request/response (via http.Hijack) and starts // the wsConnection. func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Request) { @@ -369,8 +365,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 11c97ade0..f49cfce91 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" @@ -28,7 +29,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}, @@ -46,11 +47,9 @@ 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) - - wm.SetLogger(logger) + wm := NewWebsocketManager(logger, funcMap) mux := http.NewServeMux() mux.HandleFunc("/websocket", wm.WebsocketHandler) diff --git a/rpc/jsonrpc/test/main.go b/rpc/jsonrpc/test/main.go index f11709f98..231b2bb5b 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), + "hello_world": rpcserver.NewRPCFunc(HelloWorld, "name,num"), } -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 } @@ -28,7 +27,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/jsonrpc/types/types.go b/rpc/jsonrpc/types/types.go index 74a4cc52b..d13c2b842 100644 --- a/rpc/jsonrpc/types/types.go +++ b/rpc/jsonrpc/types/types.go @@ -98,35 +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 - } - - 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 } @@ -258,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 diff --git a/rpc/test/helpers.go b/rpc/test/helpers.go index 90c3b2e49..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 } @@ -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/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 { 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..976174092 100644 --- a/test/fuzz/rpc/jsonrpc/server/handler.go +++ b/test/fuzz/rpc/jsonrpc/server/handler.go @@ -13,13 +13,13 @@ 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 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) } 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 c416a58cb..364a160ec 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" ) @@ -510,7 +510,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,