From 069e402aa1be816f35b73c0c34bac29eb893f0f9 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 28 Sep 2022 22:27:19 +0800 Subject: [PATCH] backport: add event subscription options and defaults config (#7930) (#9491) * config: add event subscription options and defaults (#7930) * Apply suggestions from code review Co-authored-by: M. J. Fromberger --- CHANGELOG_PENDING.md | 1 + config/config.go | 48 +++++++++++++++++++++++++++++++++++++++----- config/toml.go | 27 +++++++++++++++++++++++++ node/node.go | 32 ++++++++++++++++------------- 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index afe35d9c0..43949e484 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -36,6 +36,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi ### BREAKING CHANGES - CLI/RPC/Config + - [config] \#9491 Add new event subscription options and defaults. (@creachadair) - [config] \#9259 Rename the fastsync section and the fast_sync key blocksync and block_sync respectively - Apps diff --git a/config/config.go b/config/config.go index c60d37d13..ffc521a41 100644 --- a/config/config.go +++ b/config/config.go @@ -382,6 +382,33 @@ type RPCConfig struct { // predictability in subscription behavior. CloseOnSlowClient bool `mapstructure:"experimental_close_on_slow_client"` + // If true, disable the websocket interface to the RPC service. This has + // the effect of disabling the /subscribe, /unsubscribe, and /unsubscribe_all + // methods for event subscription. + // + // EXPERIMENTAL: This setting will be removed in Tendermint v0.37. + ExperimentalDisableWebsocket bool `mapstructure:"experimental-disable-websocket"` + + // The time window size for the event log. All events up to this long before + // the latest (up to EventLogMaxItems) will be available for subscribers to + // fetch via the /events method. If 0 (the default) the event log and the + // /events RPC method are disabled. + EventLogWindowSize time.Duration `mapstructure:"event-log-window-size"` + + // The maxiumum number of events that may be retained by the event log. If + // this value is 0, no upper limit is set. Otherwise, items in excess of + // this number will be discarded from the event log. + // + // Warning: This setting is a safety valve. Setting it too low may cause + // subscribers to miss events. Try to choose a value higher than the + // maximum worst-case expected event load within the chosen window size in + // ordinary operation. + // + // For example, if the window size is 10 minutes and the node typically + // averages 1000 events per ten minutes, but with occasional known spikes of + // up to 2000, choose a value > 2000. + EventLogMaxItems int `mapstructure:"event-log-max-items"` + // How long to wait for a tx to be committed during /broadcast_tx_commit // WARNING: Using a value larger than 10s will result in increasing the // global HTTP write timeout, which applies to all connections and endpoints. @@ -429,11 +456,16 @@ func DefaultRPCConfig() *RPCConfig { Unsafe: false, MaxOpenConnections: 900, - MaxSubscriptionClients: 100, - MaxSubscriptionsPerClient: 5, - SubscriptionBufferSize: defaultSubscriptionBufferSize, - TimeoutBroadcastTxCommit: 10 * time.Second, - WebSocketWriteBufferSize: defaultSubscriptionBufferSize, + SubscriptionBufferSize: defaultSubscriptionBufferSize, + WebSocketWriteBufferSize: defaultSubscriptionBufferSize, + // Settings for event subscription. + MaxSubscriptionClients: 100, + MaxSubscriptionsPerClient: 5, + ExperimentalDisableWebsocket: false, // compatible with TM v0.35 and earlier + EventLogWindowSize: 0, // disables /events RPC by default + EventLogMaxItems: 0, + + TimeoutBroadcastTxCommit: 10 * time.Second, MaxBodyBytes: int64(1000000), // 1MB MaxHeaderBytes: 1 << 20, // same as the net/http default @@ -479,6 +511,12 @@ func (cfg *RPCConfig) ValidateBasic() error { cfg.SubscriptionBufferSize, ) } + if cfg.EventLogWindowSize < 0 { + return errors.New("event-log-window-size must not be negative") + } + if cfg.EventLogMaxItems < 0 { + return errors.New("event-log-max-items must not be negative") + } if cfg.TimeoutBroadcastTxCommit < 0 { return errors.New("timeout_broadcast_tx_commit can't be negative") } diff --git a/config/toml.go b/config/toml.go index a284e4358..c27ffc1b7 100644 --- a/config/toml.go +++ b/config/toml.go @@ -233,6 +233,33 @@ experimental_websocket_write_buffer_size = {{ .RPC.WebSocketWriteBufferSize }} # predictability in subscription behavior. experimental_close_on_slow_client = {{ .RPC.CloseOnSlowClient }} +# If true, disable the websocket interface to the RPC service. This has +# the effect of disabling the /subscribe, /unsubscribe, and /unsubscribe_all +# methods for event subscription. +# +# EXPERIMENTAL: This setting will be removed in Tendermint v0.37. +experimental-disable-websocket = {{ .RPC.ExperimentalDisableWebsocket }} + +# The time window size for the event log. All events up to this long before +# the latest (up to EventLogMaxItems) will be available for subscribers to +# fetch via the /events method. If 0 (the default) the event log and the +# /events RPC method are disabled. +event-log-window-size = "{{ .RPC.EventLogWindowSize }}" + +# The maxiumum number of events that may be retained by the event log. If +# this value is 0, no upper limit is set. Otherwise, items in excess of +# this number will be discarded from the event log. +# +# Warning: This setting is a safety valve. Setting it too low may cause +# subscribers to miss events. Try to choose a value higher than the +# maximum worst-case expected event load within the chosen window size in +# ordinary operation. +# +# For example, if the window size is 10 minutes and the node typically +# averages 1000 events per ten minutes, but with occasional known spikes of +# up to 2000, choose a value > 2000. +event-log-max-items = {{ .RPC.EventLogMaxItems }} + # How long to wait for a tx to be committed during /broadcast_tx_commit. # WARNING: Using a value larger than 10s will result in increasing the # global HTTP write timeout, which applies to all connections and endpoints. diff --git a/node/node.go b/node/node.go index 902943288..4047ec096 100644 --- a/node/node.go +++ b/node/node.go @@ -1116,25 +1116,29 @@ func (n *Node) startRPC() ([]net.Listener, error) { config.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second } - // we may expose the rpc over both a unix and tcp socket + // We may expose the RPC over both TCP and a Unix-domain socket. listeners := make([]net.Listener, len(listenAddrs)) for i, listenAddr := range listenAddrs { mux := http.NewServeMux() rpcLogger := n.Logger.With("module", "rpc-server") - wmLogger := rpcLogger.With("protocol", "websocket") - wm := rpcserver.NewWebsocketManager(rpccore.Routes, - rpcserver.OnDisconnect(func(remoteAddr string) { - err := n.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(config.MaxBodyBytes), - rpcserver.WriteChanCapacity(n.config.RPC.WebSocketWriteBufferSize), - ) - wm.SetLogger(wmLogger) - mux.HandleFunc("/websocket", wm.WebsocketHandler) rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, rpcLogger) + if n.config.RPC.ExperimentalDisableWebsocket { + rpcLogger.Info("Disabling websocket endpoints (experimental-disable-websocket=true)") + } else { + wmLogger := rpcLogger.With("protocol", "websocket") + wm := rpcserver.NewWebsocketManager(rpccore.Routes, + rpcserver.OnDisconnect(func(remoteAddr string) { + err := n.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(config.MaxBodyBytes), + rpcserver.WriteChanCapacity(n.config.RPC.WebSocketWriteBufferSize), + ) + wm.SetLogger(wmLogger) + mux.HandleFunc("/websocket", wm.WebsocketHandler) + } listener, err := rpcserver.Listen( listenAddr, config,