From 185f15d64581586719c01096a81aaff7dad4c2f5 Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Wed, 30 Mar 2022 13:47:52 -0700 Subject: [PATCH 01/20] config: default indexer configuration to null (#8222) After this change, new nodes will not have indexing enabled by default. Test configurations will still use "kv". * Update pending changelog and upgrading notes. * Fix indexer config for the test app. * Update config template and enable indexing for e2e tests. --- CHANGELOG_PENDING.md | 1 + UPGRADING.md | 7 +++++++ config/config.go | 11 ++++------- config/toml.go | 4 ++-- test/app/test.sh | 25 +++++++++++++++++-------- test/docker/config-template.toml | 3 +++ test/e2e/runner/setup.go | 1 + 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index e7aa904e3..cc71a5a5e 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -20,6 +20,7 @@ Special thanks to external contributors on this release: - [config] \#7930 Add new event subscription options and defaults. (@creachadair) - [rpc] \#7982 Add new Events interface and deprecate Subscribe. (@creachadair) - [cli] \#8081 make the reset command safe to use. (@marbar3778) + - [config] \#8222 default indexer configuration to null. (@creachadair) - Apps diff --git a/UPGRADING.md b/UPGRADING.md index 49973ea52..50facec19 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -26,6 +26,13 @@ application concern so be very sure to test the application thoroughly using realistic workloads and the race detector to ensure your applications remains correct. +### Config Changes + +The default configuration for a newly-created node now disables indexing for +ABCI event metadata. Existing node configurations that already have indexing +turned on are not affected. Operators who wish to enable indexing for a new +node, however, must now edit the `config.toml` explicitly. + ### RPC Changes Tendermint v0.36 adds a new RPC event subscription API. The existing event diff --git a/config/config.go b/config/config.go index fd4923cce..42fdba7f7 100644 --- a/config/config.go +++ b/config/config.go @@ -1088,9 +1088,8 @@ type TxIndexConfig struct { // If list contains `null`, meaning no indexer service will be used. // // Options: - // 1) "null" - no indexer services. - // 2) "kv" (default) - the simplest possible indexer, - // backed by key-value storage (defaults to levelDB; see DBBackend). + // 1) "null" (default) - no indexer services. + // 2) "kv" - a simple indexer backed by key-value storage (see DBBackend) // 3) "psql" - the indexer services backed by PostgreSQL. Indexer []string `mapstructure:"indexer"` @@ -1101,14 +1100,12 @@ type TxIndexConfig struct { // DefaultTxIndexConfig returns a default configuration for the transaction indexer. func DefaultTxIndexConfig() *TxIndexConfig { - return &TxIndexConfig{ - Indexer: []string{"kv"}, - } + return &TxIndexConfig{Indexer: []string{"null"}} } // TestTxIndexConfig returns a default configuration for the transaction indexer. func TestTxIndexConfig() *TxIndexConfig { - return DefaultTxIndexConfig() + return &TxIndexConfig{Indexer: []string{"kv"}} } //----------------------------------------------------------------------------- diff --git a/config/toml.go b/config/toml.go index 7ed1aaabf..21ccfa314 100644 --- a/config/toml.go +++ b/config/toml.go @@ -520,8 +520,8 @@ peer-query-maj23-sleep-duration = "{{ .Consensus.PeerQueryMaj23SleepDuration }}" # to decide which txs to index based on configuration set in the application. # # Options: -# 1) "null" -# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). +# 1) "null" (default) - no indexer services. +# 2) "kv" - a simple indexer backed by key-value storage (see DBBackend) # 3) "psql" - the indexer services backed by PostgreSQL. # When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed. indexer = [{{ range $i, $e := .TxIndex.Indexer }}{{if $i}}, {{end}}{{ printf "%q" $e}}{{end}}] diff --git a/test/app/test.sh b/test/app/test.sh index 6896ee5f8..dba8a9c43 100755 --- a/test/app/test.sh +++ b/test/app/test.sh @@ -1,5 +1,5 @@ -#! /bin/bash -set -ex +#!/bin/bash +set -exo pipefail #- kvstore over socket, curl @@ -8,9 +8,19 @@ set -ex export PATH="$GOBIN:$PATH" export TMHOME=$HOME/.tendermint_app -function kvstore_over_socket(){ - rm -rf $TMHOME +function init_validator() { + rm -rf -- "$TMHOME" tendermint init validator + + # The default configuration sets a null indexer, but these tests require + # indexing to be enabled. Rewrite the config file to set the "kv" indexer + # before starting up the node. + sed -i'' -e '/indexer = \["null"\]/c\ +indexer = ["kv"]' "$TMHOME/config/config.toml" +} + +function kvstore_over_socket() { + init_validator echo "Starting kvstore_over_socket" abci-cli kvstore > /dev/null & pid_kvstore=$! @@ -25,9 +35,8 @@ function kvstore_over_socket(){ } # start tendermint first -function kvstore_over_socket_reorder(){ - rm -rf $TMHOME - tendermint init validator +function kvstore_over_socket_reorder() { + init_validator echo "Starting kvstore_over_socket_reorder (ie. start tendermint first)" tendermint start --mode validator > tendermint.log & pid_tendermint=$! @@ -42,7 +51,7 @@ function kvstore_over_socket_reorder(){ kill -9 $pid_kvstore $pid_tendermint } -case "$1" in +case "$1" in "kvstore_over_socket") kvstore_over_socket ;; diff --git a/test/docker/config-template.toml b/test/docker/config-template.toml index a90eb7bd5..6ce39c9f8 100644 --- a/test/docker/config-template.toml +++ b/test/docker/config-template.toml @@ -1,2 +1,5 @@ [rpc] laddr = "tcp://0.0.0.0:26657" + +[tx-index] +indexer = ["kv"] diff --git a/test/e2e/runner/setup.go b/test/e2e/runner/setup.go index 1b7d25bd7..507dc2d04 100644 --- a/test/e2e/runner/setup.go +++ b/test/e2e/runner/setup.go @@ -237,6 +237,7 @@ func MakeConfig(node *e2e.Node) (*config.Config, error) { cfg := config.DefaultConfig() cfg.Moniker = node.Name cfg.ProxyApp = AppAddressTCP + cfg.TxIndex = config.TestTxIndexConfig() if node.LogLevel != "" { cfg.LogLevel = node.LogLevel From 6ed2c42d7bebd62f37e6b0a2abb38262be05410f Mon Sep 17 00:00:00 2001 From: William Banfield <4561443+williambanfield@users.noreply.github.com> Date: Wed, 30 Mar 2022 18:11:48 -0400 Subject: [PATCH 02/20] Document steps for updating the timeout parameters. (#8217) closes: #8182 This pull request adds documentation to the `UPGRADING.md` file as well as a set of deprecation checks for the old timeout parameters in the `config.toml` file. It additionally documents the parameters in the `genesis.md`. --- UPGRADING.md | 38 ++++ cmd/tendermint/commands/root.go | 4 +- config/config.go | 57 ++++++ config/toml.go | 2 +- docs/nodes/configuration.md | 306 +++++++++++++--------------- proto/tendermint/types/params.proto | 2 +- spec/core/genesis.md | 41 ++-- 7 files changed, 258 insertions(+), 192 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index 50facec19..6ae381b7b 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -70,6 +70,44 @@ callback. For more detailed information, see [ADR 075](https://tinyurl.com/adr075) which defines and describes the new API in detail. +### Timeout Parameter Changes + +Tendermint v0.36 updates how the Tendermint consensus timing parameters are +configured. These parameters, `timeout-propose`, `timeout-propose-delta`, +`timeout-prevote`, `timeout-prevote-delta`, `timeout-precommit`, +`timeout-precommit-delta`, `timeout-commit`, and `skip-timeout-commit`, were +previously configured in `config.toml`. These timing parameters have moved and +are no longer configured in the `config.toml` file. These parameters have been +migrated into the `ConsensusParameters`. Nodes with these parameters set in the +local configuration file will see a warning logged on startup indicating that +these parameters are no longer used. + +These parameters have also been pared-down. There are no longer separate +parameters for both the `prevote` and `precommit` phases of Tendermint. The +separate `timeout-prevote` and `timeout-precommit` parameters have been merged +into a single `timeout-vote` parameter that configures both of these similar +phases of the consensus protocol. + +A set of reasonable defaults have been put in place for these new parameters +that will take effect when the node starts up in version v0.36. New chains +created using v0.36 and beyond will be able to configure these parameters in the +chain's `genesis.json` file. Chains that upgrade to v0.36 from a previous +compatible version of Tendermint will begin running with the default values. +Upgrading applications that wish to use different values from the defaults for +these parameters may do so by setting the `ConsensusParams.Timeout` field of the +`FinalizeBlock` `ABCI` response. + +As a safety measure in case of unusual timing issues during the upgrade to +v0.36, an operator may override the consensus timeout values for a single node. +Note, however, that these overrides will be removed in Tendermint v0.37. See +[configuration](https://github.com/tendermint/tendermint/blob/wb/issue-8182/docs/nodes/configuration.md) +for more information about these overrides. + +For more discussion of this, see [ADR 074](https://tinyurl.com/adr074), which +lays out the reasoning for the changes as well as [RFC +009](https://tinyurl.com/rfc009) for a discussion of the complexities of +upgrading consensus parameters. + ## v0.35 ### ABCI Changes diff --git a/cmd/tendermint/commands/root.go b/cmd/tendermint/commands/root.go index 3c9b7d049..fdee638bc 100644 --- a/cmd/tendermint/commands/root.go +++ b/cmd/tendermint/commands/root.go @@ -51,10 +51,12 @@ func RootCommand(conf *config.Config, logger log.Logger) *cobra.Command { } *conf = *pconf config.EnsureRoot(conf.RootDir) - if err := log.OverrideWithNewLogger(logger, conf.LogFormat, conf.LogLevel); err != nil { return err } + if warning := pconf.DeprecatedFieldWarning(); warning != nil { + logger.Info("WARNING", "deprecated field warning", warning) + } return nil }, diff --git a/config/config.go b/config/config.go index 42fdba7f7..500e3f7d6 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "time" "github.com/tendermint/tendermint/libs/log" @@ -145,6 +146,10 @@ func (cfg *Config) ValidateBasic() error { return nil } +func (cfg *Config) DeprecatedFieldWarning() error { + return cfg.Consensus.DeprecatedFieldWarning() +} + //----------------------------------------------------------------------------- // BaseConfig @@ -998,6 +1003,20 @@ type ConsensusConfig struct { // If it is set to true, the consensus engine will proceed to the next height // as soon as the node has gathered votes from all of the validators on the network. UnsafeBypassCommitTimeoutOverride *bool `mapstructure:"unsafe-bypass-commit-timeout-override"` + + // Deprecated timeout parameters. These parameters are present in this struct + // so that they can be parsed so that validation can check if they have erroneously + // been included and provide a helpful error message. + // These fields should be completely removed in v0.37. + // See: https://github.com/tendermint/tendermint/issues/8188 + DeprecatedTimeoutPropose *interface{} `mapstructure:"timeout-propose"` + DeprecatedTimeoutProposeDelta *interface{} `mapstructure:"timeout-propose-delta"` + DeprecatedTimeoutPrevote *interface{} `mapstructure:"timeout-prevote"` + DeprecatedTimeoutPrevoteDelta *interface{} `mapstructure:"timeout-prevote-delta"` + DeprecatedTimeoutPrecommit *interface{} `mapstructure:"timeout-precommit"` + DeprecatedTimeoutPrecommitDelta *interface{} `mapstructure:"timeout-precommit-delta"` + DeprecatedTimeoutCommit *interface{} `mapstructure:"timeout-commit"` + DeprecatedSkipTimeoutCommit *interface{} `mapstructure:"skip-timeout-commit"` } // DefaultConsensusConfig returns a default configuration for the consensus service @@ -1072,6 +1091,44 @@ func (cfg *ConsensusConfig) ValidateBasic() error { return nil } +func (cfg *ConsensusConfig) DeprecatedFieldWarning() error { + var fields []string + if cfg.DeprecatedSkipTimeoutCommit != nil { + fields = append(fields, "skip-timeout-commit") + } + if cfg.DeprecatedTimeoutPropose != nil { + fields = append(fields, "timeout-propose") + } + if cfg.DeprecatedTimeoutProposeDelta != nil { + fields = append(fields, "timeout-propose-delta") + } + if cfg.DeprecatedTimeoutPrevote != nil { + fields = append(fields, "timeout-prevote") + } + if cfg.DeprecatedTimeoutPrevoteDelta != nil { + fields = append(fields, "timeout-prevote-delta") + } + if cfg.DeprecatedTimeoutPrecommit != nil { + fields = append(fields, "timeout-precommit") + } + if cfg.DeprecatedTimeoutPrecommitDelta != nil { + fields = append(fields, "timeout-precommit-delta") + } + if cfg.DeprecatedTimeoutCommit != nil { + fields = append(fields, "timeout-commit") + } + if cfg.DeprecatedSkipTimeoutCommit != nil { + fields = append(fields, "skip-timeout-commit") + } + if len(fields) != 0 { + return fmt.Errorf("the following deprecated fields were set in the "+ + "configuration file: %s. These fields were removed in v0.36. Timeout "+ + "configuration has been moved to the ConsensusParams. For more information see "+ + "https://tinyurl.com/adr074", strings.Join(fields, ", ")) + } + return nil +} + //----------------------------------------------------------------------------- // TxIndexConfig // Remember that Event has the following structure: diff --git a/config/toml.go b/config/toml.go index 21ccfa314..7f49249e9 100644 --- a/config/toml.go +++ b/config/toml.go @@ -486,7 +486,7 @@ peer-query-maj23-sleep-duration = "{{ .Consensus.PeerQueryMaj23SleepDuration }}" # This field provides an unsafe override of the Vote timeout consensus parameter. # This field configures how long the consensus engine will wait after -# receiving +2/3 votes in a around. +# receiving +2/3 votes in a round. # If this field is set to a value greater than 0, it will take effect. # unsafe-vote-timeout-override = {{ .Consensus.UnsafeVoteTimeoutOverride }} diff --git a/docs/nodes/configuration.md b/docs/nodes/configuration.md index ebd21d998..a55bfb63a 100644 --- a/docs/nodes/configuration.md +++ b/docs/nodes/configuration.md @@ -16,7 +16,8 @@ the parameters set with their default values. It will look something like the file below, however, double check by inspecting the `config.toml` created with your version of `tendermint` installed: -```toml# This is a TOML config file. +```toml +# This is a TOML config file. # For more information, see https://github.com/toml-lang/toml # NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or @@ -33,11 +34,10 @@ like the file below, however, double check by inspecting the proxy-app = "tcp://127.0.0.1:26658" # A custom human readable name for this node -moniker = "ape" +moniker = "sidewinder" - -# Mode of Node: full | validator | seed (default: "validator") -# * validator node (default) +# Mode of Node: full | validator | seed +# * validator node # - all reactors # - with priv_validator_key.json, priv_validator_state.json # * full node @@ -48,11 +48,6 @@ moniker = "ape" # - No priv_validator_key.json, priv_validator_state.json mode = "validator" -# If this node is many blocks behind the tip of the chain, FastSync -# allows them to catchup quickly by downloading blocks in parallel -# and verifying their commits -fast-sync = true - # Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb # * goleveldb (github.com/syndtr/goleveldb - most popular implementation) # - pure go @@ -120,10 +115,10 @@ laddr = "" client-certificate-file = "" # Client key generated while creating certificates for secure connection -validator-client-key-file = "" +client-key-file = "" # Path to the Root Certificate Authority used to sign both client and server certificates -certificate-authority = "" +root-ca-file = "" ####################################################################### @@ -149,26 +144,10 @@ cors-allowed-methods = ["HEAD", "GET", "POST", ] # A list of non simple headers the client is allowed to use with cross-domain requests cors-allowed-headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] -# TCP or UNIX socket address for the gRPC server to listen on -# NOTE: This server only supports /broadcast_tx_commit -# Deprecated gRPC in the RPC layer of Tendermint will be deprecated in 0.36. -grpc-laddr = "" - -# Maximum number of simultaneous connections. -# Does not include RPC (HTTP&WebSocket) connections. See max-open-connections -# If you want to accept a larger number than the default, make sure -# you increase your OS limits. -# 0 - unlimited. -# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} -# 1024 - 40 - 10 - 50 = 924 = ~900 -# Deprecated gRPC in the RPC layer of Tendermint will be deprecated in 0.36. -grpc-max-open-connections = 900 - # Activate unsafe RPC commands like /dial-seeds and /unsafe-flush-mempool unsafe = false # Maximum number of simultaneous connections (including WebSocket). -# Does not include gRPC connections. See grpc-max-open-connections # If you want to accept a larger number than the default, make sure # you increase your OS limits. # 0 - unlimited. @@ -182,10 +161,37 @@ max-open-connections = 900 max-subscription-clients = 100 # Maximum number of unique queries a given client can /subscribe to -# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to -# the estimated # maximum number of broadcast_tx_commit calls per block. +# If you're using a Local RPC client and /broadcast_tx_commit, set this +# to the estimated maximum number of broadcast_tx_commit calls per block. max-subscriptions-per-client = 5 +# 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 = false + +# 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 = "0s" + +# 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 = 0 + # 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. @@ -252,63 +258,12 @@ persistent-peers = "" # UPNP port forwarding upnp = false -# Path to address book -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -addr-book-file = "config/addrbook.json" - -# Set true for strict address routability rules -# Set false for private or local networks -addr-book-strict = true - -# Maximum number of inbound peers -# -# TODO: Remove once p2p refactor is complete in favor of MaxConnections. -# ref: https://github.com/tendermint/tendermint/issues/5670 -max-num-inbound-peers = 40 - -# Maximum number of outbound peers to connect to, excluding persistent peers -# -# TODO: Remove once p2p refactor is complete in favor of MaxConnections. -# ref: https://github.com/tendermint/tendermint/issues/5670 -max-num-outbound-peers = 10 - # Maximum number of connections (inbound and outbound). max-connections = 64 # Rate limits the number of incoming connection attempts per IP address. max-incoming-connection-attempts = 100 -# List of node IDs, to which a connection will be (re)established ignoring any existing limits -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -unconditional-peer-ids = "" - -# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -persistent-peers-max-dial-period = "0s" - -# Time to wait before flushing messages out on the connection -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -flush-throttle-timeout = "100ms" - -# Maximum size of a message packet payload, in bytes -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -max-packet-msg-payload-size = 1400 - -# Rate at which packets can be sent, in bytes/second -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -send-rate = 5120000 - -# Rate at which packets can be received, in bytes/second -# TODO: Remove once p2p refactor is complete -# ref: https:#github.com/tendermint/tendermint/issues/5670 -recv-rate = 5120000 - # Set true to enable the peer-exchange reactor pex = true @@ -323,16 +278,28 @@ allow-duplicate-ip = false handshake-timeout = "20s" dial-timeout = "3s" +# Time to wait before flushing messages out on the connection +# TODO: Remove once MConnConnection is removed. +flush-throttle-timeout = "100ms" + +# Maximum size of a message packet payload, in bytes +# TODO: Remove once MConnConnection is removed. +max-packet-msg-payload-size = 1400 + +# Rate at which packets can be sent, in bytes/second +# TODO: Remove once MConnConnection is removed. +send-rate = 5120000 + +# Rate at which packets can be received, in bytes/second +# TODO: Remove once MConnConnection is removed. +recv-rate = 5120000 + + ####################################################### ### Mempool Configuration Option ### ####################################################### [mempool] -# Mempool version to use: -# 1) "v0" - The legacy non-prioritized mempool reactor. -# 2) "v1" (default) - The prioritized mempool reactor. -version = "v1" - recheck = true broadcast = true @@ -388,22 +355,30 @@ ttl-num-blocks = 0 # starting from the height of the snapshot. enable = false -# RPC servers (comma-separated) for light client verification of the synced state machine and -# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding -# header hash obtained from a trusted source, and a period during which validators can be trusted. -# -# For Cosmos SDK-based chains, trust-period should usually be about 2/3 of the unbonding time (~2 -# weeks) during which they can be financially punished (slashed) for misbehavior. +# State sync uses light client verification to verify state. This can be done either through the +# P2P layer or RPC layer. Set this to true to use the P2P layer. If false (default), RPC layer +# will be used. +use-p2p = false + +# If using RPC, at least two addresses need to be provided. They should be compatible with net.Dial, +# for example: "host.example.com:2125" rpc-servers = "" + +# The hash and height of a trusted block. Must be within the trust-period. trust-height = 0 trust-hash = "" + +# The trust period should be set so that Tendermint can detect and gossip misbehavior before +# it is considered expired. For chains based on the Cosmos SDK, one day less than the unbonding +# period should suffice. trust-period = "168h0m0s" # Time to spend discovering snapshots before initiating a restore. discovery-time = "15s" -# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). -# Will create a new, randomly named directory within, and remove it when done. +# Temporary directory for state sync snapshot chunks, defaults to os.TempDir(). +# The synchronizer will create a new, randomly named directory within this directory +# and remove it when the sync is complete. temp-dir = "" # The timeout duration before re-requesting a chunk, possibly from a different @@ -413,21 +388,6 @@ chunk-request-timeout = "15s" # The number of concurrent chunk and block fetchers to run (default: 4). fetchers = "4" -####################################################### -### Block Sync Configuration Connections ### -####################################################### -[blocksync] - -# If this node is many blocks behind the tip of the chain, BlockSync -# allows them to catchup quickly by downloading blocks in parallel -# and verifying their commits -enable = true - -# Block Sync version to use: -# 1) "v0" (default) - the standard block sync implementation -# 2) "v2" - DEPRECATED, please use v0 -version = "v0" - ####################################################### ### Consensus Configuration Options ### ####################################################### @@ -435,32 +395,12 @@ version = "v0" wal-file = "data/cs.wal/wal" -# How long we wait for a proposal block before prevoting nil -timeout-propose = "3s" -# How much timeout-propose increases with each round -timeout-propose-delta = "500ms" -# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) -timeout-prevote = "1s" -# How much the timeout-prevote increases with each round -timeout-prevote-delta = "500ms" -# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) -timeout-precommit = "1s" -# How much the timeout-precommit increases with each round -timeout-precommit-delta = "500ms" -# How long we wait after committing a block, before starting on the new -# height (this gives us a chance to receive some more precommits, even -# though we already have +2/3). -timeout-commit = "1s" - # How many blocks to look back to check existence of the node's consensus votes before joining consensus # When non-zero, the node will panic upon restart # if the same consensus key was used to sign {double-sign-check-height} last blocks. # So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. double-sign-check-height = 0 -# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) -skip-timeout-commit = false - # EmptyBlocks mode and possible interval between empty blocks create-empty-blocks = true create-empty-blocks-interval = "0s" @@ -469,6 +409,50 @@ create-empty-blocks-interval = "0s" peer-gossip-sleep-duration = "100ms" peer-query-maj23-sleep-duration = "2s" +### Unsafe Timeout Overrides ### + +# These fields provide temporary overrides for the Timeout consensus parameters. +# Use of these parameters is strongly discouraged. Using these parameters may have serious +# liveness implications for the validator and for the chain. +# +# These fields will be removed from the configuration file in the v0.37 release of Tendermint. +# For additional information, see ADR-74: +# https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-074-timeout-params.md + +# This field provides an unsafe override of the Propose timeout consensus parameter. +# This field configures how long the consensus engine will wait for a proposal block before prevoting nil. +# If this field is set to a value greater than 0, it will take effect. +# unsafe-propose-timeout-override = 0s + +# This field provides an unsafe override of the ProposeDelta timeout consensus parameter. +# This field configures how much the propose timeout increases with each round. +# If this field is set to a value greater than 0, it will take effect. +# unsafe-propose-timeout-delta-override = 0s + +# This field provides an unsafe override of the Vote timeout consensus parameter. +# This field configures how long the consensus engine will wait after +# receiving +2/3 votes in a around. +# If this field is set to a value greater than 0, it will take effect. +# unsafe-vote-timeout-override = 0s + +# This field provides an unsafe override of the VoteDelta timeout consensus parameter. +# This field configures how much the vote timeout increases with each round. +# If this field is set to a value greater than 0, it will take effect. +# unsafe-vote-timeout-delta-override = 0s + +# This field provides an unsafe override of the Commit timeout consensus parameter. +# This field configures how long the consensus engine will wait after receiving +# +2/3 precommits before beginning the next height. +# If this field is set to a value greater than 0, it will take effect. +# unsafe-commit-timeout-override = 0s + +# This field provides an unsafe override of the BypassCommitTimeout consensus parameter. +# This field configures if the consensus engine will wait for the full Commit timeout +# before proceeding to the next height. +# If this field is set to true, the consensus engine will proceed to the next height +# as soon as the node has gathered votes from all of the validators on the network. +# unsafe-bypass-commit-timeout-override = + ####################################################### ### Transaction Indexer Configuration Options ### ####################################################### @@ -543,46 +527,6 @@ transactions every `create-empty-blocks-interval`. For instance, with Tendermint will only create blocks if there are transactions, or after waiting 30 seconds without receiving any transactions. -## Consensus timeouts explained - -There's a variety of information about timeouts in [Running in -production](../tendermint-core/running-in-production.md) - -You can also find more detailed technical explanation in the spec: [The latest -gossip on BFT consensus](https://arxiv.org/abs/1807.04938). - -```toml -[consensus] -... - -timeout-propose = "3s" -timeout-propose-delta = "500ms" -timeout-prevote = "1s" -timeout-prevote-delta = "500ms" -timeout-precommit = "1s" -timeout-precommit-delta = "500ms" -timeout-commit = "1s" -``` - -Note that in a successful round, the only timeout that we absolutely wait no -matter what is `timeout-commit`. - -Here's a brief summary of the timeouts: - -- `timeout-propose` = how long we wait for a proposal block before prevoting - nil -- `timeout-propose-delta` = how much timeout-propose increases with each round -- `timeout-prevote` = how long we wait after receiving +2/3 prevotes for - anything (ie. not a single block or nil) -- `timeout-prevote-delta` = how much the timeout-prevote increases with each - round -- `timeout-precommit` = how long we wait after receiving +2/3 precommits for - anything (ie. not a single block or nil) -- `timeout-precommit-delta` = how much the timeout-precommit increases with - each round -- `timeout-commit` = how long we wait after committing a block, before starting - on the new height (this gives us a chance to receive some more precommits, - even though we already have +2/3) ## P2P settings @@ -648,3 +592,27 @@ Example: ```shell $ psql ... -f state/indexer/sink/psql/schema.sql ``` + +## Unsafe Consensus Timeout Overrides + +Tendermint version v0.36 provides a set of unsafe overrides for the consensus +timing parameters. These parameters are provided as a safety measure in case of +unusual timing issues during the upgrade to v0.36 so that an operator may +override the timings for a single node. These overrides will completely be +removed in Tendermint v0.37. + +- `unsafe-propose-override`: How long the Tendermint consensus engine will wait + for a proposal block before prevoting nil. +- `unsafe-propose-delta-override`: How much the propose timeout increase with + each round. +- `unsafe-vote-override`: How long the consensus engine will wait after + receiving +2/3 votes in a round. +- `unsafe-vote-delta-override`: How much the vote timeout increases with each + round. +- `unsafe-commit-override`: How long the consensus engine will wait after + receiving +2/3 precommits before beginning the next height. +- `unsafe-bypass-commit-timeout-override`: Configures if the consensus engine + will wait for the full commit timeout before proceeding to the next height. If + this field is set to true, the consensus engine will proceed to the next + height as soon as the node has gathered votes from all of the validators on + the network. diff --git a/proto/tendermint/types/params.proto b/proto/tendermint/types/params.proto index dcb4d11ba..466ba464f 100644 --- a/proto/tendermint/types/params.proto +++ b/proto/tendermint/types/params.proto @@ -75,7 +75,7 @@ message HashedParams { // see the specification of proposer-based timestamps: // https://github.com/tendermint/tendermint/tree/master/spec/consensus/proposer-based-timestamp message SynchronyParams { - // message_delay bounds how long a proposal message may take to reach all validators on a newtork + // message_delay bounds how long a proposal message may take to reach all validators on a network // and still be considered valid. google.protobuf.Duration message_delay = 1 [(gogoproto.stdduration) = true]; // precision bounds how skewed a proposer's clock may be from any validator diff --git a/spec/core/genesis.md b/spec/core/genesis.md index 1dc019e77..5bf6156fd 100644 --- a/spec/core/genesis.md +++ b/spec/core/genesis.md @@ -4,31 +4,32 @@ The genesis file is the starting point of a chain. An application will populate ## Genesis Fields -- `genesis_time`: The genesis time is the time the blockchain started or will start. If nodes are started before this time they will sit idle until the time specified. -- `chain_id`: The chainid is the chain identifier. Every chain should have a unique identifier. When conducting a fork based upgrade, we recommend changing the chainid to avoid network or consensus errors. -- `initial_height`: This field is the starting height of the blockchain. When conducting a chain restart to avoid restarting at height 1, the network is able to start at a specified height. +- `genesis_time`: The time the blockchain started or will start. If nodes are started before this time they will sit idle until the time specified. +- `chain_id`: The chain identifier. Every chain should have a unique identifier. When conducting a fork based upgrade, we recommend changing the chainid to avoid network or consensus errors. +- `initial_height`: The starting height of the blockchain. When conducting a chain restart to avoid restarting at height 1, the network is able to start at a specified height. - `consensus_params` - `block` - `max_bytes`: The max amount of bytes a block can be. - `max_gas`: The maximum amount of gas that a block can have. - - `time_iota_ms`: This parameter has no value anymore in Tendermint-core. - -- `evidence` - - `max_age_num_blocks`: After this preset amount of blocks has passed a single piece of evidence is considered invalid - - `max_age_duration`: After this preset amount of time has passed a single piece of evidence is considered invalid. - - `max_bytes`: The max amount of bytes of all evidence included in a block. - -> Note: For evidence to be considered invalid, evidence must be older than both `max_age_num_blocks` and `max_age_duration` - -- `validator` - - `pub_key_types`: Defines which curves are to be accepted as a valid validator consensus key. Tendermint supports ed25519, sr25519 and secp256k1. - -- `version` - - `app_version`: The version of the application. This is set by the application and is used to identify which version of the app a user should be using in order to operate a node. - + - `evidence` + - `max_age_num_blocks`: After this preset amount of blocks has passed a single piece of evidence is considered invalid. + - `max_age_duration`: After this preset amount of time has passed a single piece of evidence is considered invalid. + - `max_bytes`: The max amount of bytes of all evidence included in a block. + - `validator` + - `pub_key_types`: Defines which curves are to be accepted as a valid validator consensus key. Tendermint supports ed25519, sr25519 and secp256k1. + - `version` + - `app_version`: The version of the application. This is set by the application and is used to identify which version of the app a user should be using in order to operate a node. + - `synchrony` + - `message_delay`: A bound on how long a proposal message may take to reach all validators on a network and still be considered valid. + - `precision`: A bound on how skewed the proposer's clock may be from any validator on the network while still producing valid proposals. + - `timeout` + - `propose`: How long the Tendermint consensus engine will wait for a proposal block before prevoting nil. + - `propose_delta`: How much the propose timeout increase with each round. + - `vote`: How long the consensus engine will wait after receiving +2/3 votes in a round. + - `vote_delta`: How much the vote timeout increases with each round. + - `commit`: How long the consensus engine will wait after receiving +2/3 precommits before beginning the next height. + - `bypass_commit_timeout`: Configures if the consensus engine will wait for the full commit timeout before proceeding to the next height. If this field is set to true, the conesnsus engine will proceed to the next height as soon as the node has gathered votes from all of the validators on the network. - `validators` - This is an array of validators. This validator set is used as the starting validator set of the chain. This field can be empty, if the application sets the validator set in `InitChain`. - - `app_hash`: The applications state root hash. This field does not need to be populated at the start of the chain, the application may provide the needed information via `Initchain`. - - `app_state`: This section is filled in by the application and is unknown to Tendermint. From d1722c9c10947f50bfa910472512277807e0ebeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 12:58:41 +0000 Subject: [PATCH 03/20] build(deps): Bump github.com/vektra/mockery/v2 from 2.10.0 to 2.10.1 (#8226) Bumps [github.com/vektra/mockery/v2](https://github.com/vektra/mockery) from 2.10.0 to 2.10.1.
Release notes

Sourced from github.com/vektra/mockery/v2's releases.

v2.10.1

Changelog

  • fa0080c Fix config.GetSemverInfo() for Go 1.18
  • 4e181be Load packages with dependencies for Go 1.18
  • 232f954 Merge pull request #435 from emmanuel099/master
  • b11695e Merge pull request #436 from emmanuel099/test_with_3.18
  • e0e183b Test with Go 1.18
  • adda07f Update README.md
  • 5f5570d Update README.md
  • 4fc5912 Update README.md
  • fa2d82d Update README.md
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/vektra/mockery/v2&package-manager=go_modules&previous-version=2.10.0&new-version=2.10.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ed88618e0..21afc3375 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/creachadair/atomicfile v0.2.4 github.com/golangci/golangci-lint v1.45.2 github.com/google/go-cmp v0.5.7 - github.com/vektra/mockery/v2 v2.10.0 + github.com/vektra/mockery/v2 v2.10.1 gotest.tools v2.2.0+incompatible ) diff --git a/go.sum b/go.sum index 8ba897684..19aeb8f1f 100644 --- a/go.sum +++ b/go.sum @@ -1035,8 +1035,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vektra/mockery/v2 v2.10.0 h1:MiiQWxwdq7/ET6dCXLaJzSGEN17k758H7JHS9kOdiks= -github.com/vektra/mockery/v2 v2.10.0/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4= +github.com/vektra/mockery/v2 v2.10.1 h1:EOsWLFVlkUJlNurdO/w1NBFbFE1vbemJJtaG3Bo6H/M= +github.com/vektra/mockery/v2 v2.10.1/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= From 6af23ff757fd3a293b931b4fb841e9dad665bf82 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Thu, 31 Mar 2022 09:10:09 -0400 Subject: [PATCH 04/20] state: avoid premature genericism (#8224) --- internal/blocksync/reactor_test.go | 1 + internal/consensus/byzantine_test.go | 2 +- internal/consensus/common_test.go | 2 +- internal/consensus/reactor_test.go | 2 +- internal/consensus/replay.go | 4 ++-- internal/consensus/replay_file.go | 2 +- internal/consensus/replay_test.go | 2 +- internal/consensus/wal_generator.go | 2 +- internal/state/execution.go | 20 +++----------------- internal/state/execution_test.go | 16 ++++++++++++---- internal/state/validation_test.go | 3 +++ node/node.go | 2 +- node/node_test.go | 3 +++ 13 files changed, 31 insertions(+), 30 deletions(-) diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index 5d70c27ca..e35d45a74 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -145,6 +145,7 @@ func (rts *reactorTestSuite) addNode( sm.EmptyEvidencePool{}, blockStore, eventbus, + sm.NopMetrics(), ) for blockHeight := int64(1); blockHeight <= maxBlockHeight; blockHeight++ { diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index 40a37b812..f631452bd 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -95,7 +95,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { evpool := evidence.NewPool(logger.With("module", "evidence"), evidenceDB, stateStore, blockStore, evidence.NopMetrics(), eventBus) // Make State - blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyAppConnCon, mempool, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyAppConnCon, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) cs, err := NewState(ctx, logger, thisConfig.Consensus, stateStore, blockExec, blockStore, mempool, evpool, eventBus) require.NoError(t, err) // set private validator diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index 6abe14f60..a69fc1240 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -490,7 +490,7 @@ func newStateWithConfigAndBlockStore( eventBus := eventbus.NewDefault(logger.With("module", "events")) require.NoError(t, eventBus.Start(ctx)) - blockExec := sm.NewBlockExecutor(stateStore, logger, proxyAppConnCon, mempool, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, logger, proxyAppConnCon, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) cs, err := NewState(ctx, logger.With("module", "consensus"), thisConfig.Consensus, diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index a84aa8bde..886e3794a 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -504,7 +504,7 @@ func TestReactorWithEvidence(t *testing.T) { eventBus := eventbus.NewDefault(log.NewNopLogger().With("module", "events")) require.NoError(t, eventBus.Start(ctx)) - blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyAppConnCon, mempool, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyAppConnCon, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) cs, err := NewState(ctx, logger.With("validator", i, "module", "consensus"), thisConfig.Consensus, stateStore, blockExec, blockStore, mempool, evpool2, eventBus) diff --git a/internal/consensus/replay.go b/internal/consensus/replay.go index 5d097df21..177b9fbad 100644 --- a/internal/consensus/replay.go +++ b/internal/consensus/replay.go @@ -484,7 +484,7 @@ func (h *Handshaker) replayBlocks( if i == finalBlock && !mutateState { // We emit events for the index services at the final block due to the sync issue when // the node shutdown during the block committing status. - blockExec := sm.NewBlockExecutor(h.stateStore, h.logger, appClient, emptyMempool{}, sm.EmptyEvidencePool{}, h.store, h.eventBus) + blockExec := sm.NewBlockExecutor(h.stateStore, h.logger, appClient, emptyMempool{}, sm.EmptyEvidencePool{}, h.store, h.eventBus, sm.NopMetrics()) appHash, err = sm.ExecCommitBlock(ctx, blockExec, appClient, block, h.logger, h.stateStore, h.genDoc.InitialHeight, state) if err != nil { @@ -526,7 +526,7 @@ func (h *Handshaker) replayBlock( // Use stubs for both mempool and evidence pool since no transactions nor // evidence are needed here - block already exists. - blockExec := sm.NewBlockExecutor(h.stateStore, h.logger, appClient, emptyMempool{}, sm.EmptyEvidencePool{}, h.store, h.eventBus) + blockExec := sm.NewBlockExecutor(h.stateStore, h.logger, appClient, emptyMempool{}, sm.EmptyEvidencePool{}, h.store, h.eventBus, sm.NopMetrics()) var err error state, err = blockExec.ApplyBlock(ctx, state, meta.BlockID, block) diff --git a/internal/consensus/replay_file.go b/internal/consensus/replay_file.go index 492d1d1ee..e88a06454 100644 --- a/internal/consensus/replay_file.go +++ b/internal/consensus/replay_file.go @@ -348,7 +348,7 @@ func newConsensusStateForReplay( } mempool, evpool := emptyMempool{}, sm.EmptyEvidencePool{} - blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mempool, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) consensusState, err := NewState(ctx, logger, csConfig, stateStore, blockExec, blockStore, mempool, evpool, eventBus) diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index d24e55d67..468d912ac 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -826,7 +826,7 @@ func applyBlock( eventBus *eventbus.EventBus, ) sm.State { testPartSize := types.BlockPartSizeBytes - blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), appClient, mempool, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), appClient, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) bps, err := blk.MakePartSet(testPartSize) require.NoError(t, err) diff --git a/internal/consensus/wal_generator.go b/internal/consensus/wal_generator.go index b11930f16..8c61c1203 100644 --- a/internal/consensus/wal_generator.go +++ b/internal/consensus/wal_generator.go @@ -80,7 +80,7 @@ func WALGenerateNBlocks(ctx context.Context, t *testing.T, logger log.Logger, wr mempool := emptyMempool{} evpool := sm.EmptyEvidencePool{} - blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyApp, mempool, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyApp, mempool, evpool, blockStore, eventBus, sm.NopMetrics()) consensusState, err := NewState(ctx, logger, cfg.Consensus, stateStore, blockExec, blockStore, mempool, evpool, eventBus) if err != nil { t.Fatal(err) diff --git a/internal/state/execution.go b/internal/state/execution.go index 4f02092d5..bd800ae8e 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -48,14 +48,6 @@ type BlockExecutor struct { cache map[string]struct{} } -type BlockExecutorOption func(executor *BlockExecutor) - -func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption { - return func(blockExec *BlockExecutor) { - blockExec.metrics = metrics - } -} - // NewBlockExecutor returns a new BlockExecutor with a NopEventBus. // Call SetEventBus to provide one. func NewBlockExecutor( @@ -66,25 +58,19 @@ func NewBlockExecutor( evpool EvidencePool, blockStore BlockStore, eventBus *eventbus.EventBus, - options ...BlockExecutorOption, + metrics *Metrics, ) *BlockExecutor { - res := &BlockExecutor{ + return &BlockExecutor{ eventBus: eventBus, store: stateStore, appClient: appClient, mempool: pool, evpool: evpool, logger: logger, - metrics: NopMetrics(), + metrics: metrics, cache: make(map[string]struct{}), blockStore: blockStore, } - - for _, option := range options { - option(res) - } - - return res } func (blockExec *BlockExecutor) Store() Store { diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index 58580e7be..9c5042645 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -64,7 +64,7 @@ func TestApplyBlock(t *testing.T) { mock.Anything, mock.Anything, mock.Anything).Return(nil) - blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mp, sm.EmptyEvidencePool{}, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mp, sm.EmptyEvidencePool{}, blockStore, eventBus, sm.NopMetrics()) block := sf.MakeBlock(state, 1, new(types.Commit)) bps, err := block.MakePartSet(testPartSize) @@ -128,7 +128,7 @@ func TestFinalizeBlockDecidedLastCommit(t *testing.T) { eventBus := eventbus.NewDefault(logger) require.NoError(t, eventBus.Start(ctx)) - blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), appClient, mp, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), appClient, mp, evpool, blockStore, eventBus, sm.NopMetrics()) state, _, lastCommit := makeAndCommitGoodBlock(ctx, t, state, 1, new(types.Commit), state.NextValidators.Validators[0].Address, blockExec, privVals, nil) for idx, isAbsent := range tc.absentCommitSigs { @@ -252,8 +252,7 @@ func TestFinalizeBlockByzantineValidators(t *testing.T) { blockStore := store.NewBlockStore(dbm.NewMemDB()) - blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyApp, - mp, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.NewNopLogger(), proxyApp, mp, evpool, blockStore, eventBus, sm.NopMetrics()) block := sf.MakeBlock(state, 1, new(types.Commit)) block.Evidence = ev @@ -298,6 +297,7 @@ func TestProcessProposal(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) block0 := sf.MakeBlock(state, height-1, new(types.Commit)) @@ -515,6 +515,7 @@ func TestFinalizeBlockValidatorUpdates(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) updatesSub, err := eventBus.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{ @@ -585,6 +586,7 @@ func TestFinalizeBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) block := sf.MakeBlock(state, 1, new(types.Commit)) @@ -646,6 +648,7 @@ func TestEmptyPrepareProposal(t *testing.T) { sm.EmptyEvidencePool{}, nil, eventBus, + sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) @@ -700,6 +703,7 @@ func TestPrepareProposalPanicOnInvalid(t *testing.T) { evpool, nil, eventBus, + sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) @@ -757,6 +761,7 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { evpool, nil, eventBus, + sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) @@ -816,6 +821,7 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { evpool, nil, eventBus, + sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) @@ -872,6 +878,7 @@ func TestPrepareProposalReorderTxs(t *testing.T) { evpool, nil, eventBus, + sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) @@ -935,6 +942,7 @@ func TestPrepareProposalModifiedTxStatusFalse(t *testing.T) { evpool, nil, eventBus, + sm.NopMetrics(), ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index b7b56adb8..e111ec6cc 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -63,6 +63,7 @@ func TestValidateBlockHeader(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -166,6 +167,7 @@ func TestValidateBlockCommit(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) wrongSigsCommit := types.NewCommit(1, 0, types.BlockID{}, nil) @@ -315,6 +317,7 @@ func TestValidateBlockEvidence(t *testing.T) { evpool, blockStore, eventBus, + sm.NopMetrics(), ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) diff --git a/node/node.go b/node/node.go index 35be24330..34350e09f 100644 --- a/node/node.go +++ b/node/node.go @@ -289,7 +289,7 @@ func makeNode( evPool, blockStore, eventBus, - sm.BlockExecutorWithMetrics(nodeMetrics.state), + nodeMetrics.state, ) // Determine whether we should do block sync. This must happen after the handshake, since the diff --git a/node/node_test.go b/node/node_test.go index e70be984f..a03d7286e 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -333,6 +333,7 @@ func TestCreateProposalBlock(t *testing.T) { evidencePool, blockStore, eventBus, + sm.NopMetrics(), ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) @@ -412,6 +413,7 @@ func TestMaxTxsProposalBlockSize(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) @@ -487,6 +489,7 @@ func TestMaxProposalBlockSize(t *testing.T) { sm.EmptyEvidencePool{}, blockStore, eventBus, + sm.NopMetrics(), ) blockID := types.BlockID{ From a79dd42d2486628415cf1cc476f737605479ff70 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Thu, 31 Mar 2022 14:37:13 -0400 Subject: [PATCH 05/20] lint: bump linter version in ci (#8234) --- .github/workflows/lint.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e22dde8fc..fa8f153f1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,7 +1,11 @@ name: Golang Linter -# Lint runs golangci-lint over the entire Tendermint repository -# This workflow is run on every pull request and push to master -# The `golangci` job will pass without running if no *.{go, mod, sum} files have been modified. +# Lint runs golangci-lint over the entire Tendermint repository. +# +# This workflow is run on every pull request and push to master. +# +# The `golangci` job will pass without running if no *.{go, mod, sum} +# files have been modified. + on: pull_request: push: @@ -25,8 +29,10 @@ jobs: go.sum - uses: golangci/golangci-lint-action@v3.1.0 with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.44 + # Required: the version of golangci-lint is required and + # must be specified without patch version: we always use the + # latest patch version. + version: v1.45 args: --timeout 10m github-token: ${{ secrets.github_token }} if: env.GIT_DIFF From b68424be47059fe9f8528e121cb2c3880c672883 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Thu, 31 Mar 2022 14:48:26 -0400 Subject: [PATCH 06/20] light: remove untracked close channel (#8228) --- light/rpc/client.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/light/rpc/client.go b/light/rpc/client.go index f1c21c994..aedf15050 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -51,7 +51,6 @@ type Client struct { keyPathFn KeyPathFunc closers []func() - quitCh chan struct{} } var _ rpcclient.Client = (*Client)(nil) @@ -92,10 +91,9 @@ func DefaultMerkleKeyPathFn() KeyPathFunc { // NewClient returns a new client. func NewClient(logger log.Logger, next rpcclient.Client, lc LightClient, opts ...Option) *Client { c := &Client{ - next: next, - lc: lc, - prt: merkle.DefaultProofRuntime(), - quitCh: make(chan struct{}), + next: next, + lc: lc, + prt: merkle.DefaultProofRuntime(), } c.BaseService = *service.NewBaseService(logger, "Client", c) for _, o := range opts { @@ -111,10 +109,6 @@ func (c *Client) OnStart(ctx context.Context) error { return err } c.closers = append(c.closers, ncancel) - go func() { - defer close(c.quitCh) - c.Wait() - }() return nil } From 4a504c068762a868de13270ac20ad890cac2ebd4 Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Thu, 31 Mar 2022 22:21:25 +0200 Subject: [PATCH 07/20] e2e: Fix hashing for app + Fix logic of TestApp_Hash (#8229) * Fix hashing of e2e App * Fix TestApp_Hash * CaMeL * Update test/e2e/app/state.go Co-authored-by: M. J. Fromberger * for-->Eventually + if-->require * Update test/e2e/tests/app_test.go Co-authored-by: Sam Kleinman * fix lint Co-authored-by: M. J. Fromberger Co-authored-by: Sam Kleinman --- test/e2e/app/snapshots.go | 2 +- test/e2e/app/state.go | 12 ++++++++---- test/e2e/tests/app_test.go | 27 ++++++++++++++------------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/test/e2e/app/snapshots.go b/test/e2e/app/snapshots.go index 65edbc3a5..61e34bd07 100644 --- a/test/e2e/app/snapshots.go +++ b/test/e2e/app/snapshots.go @@ -92,7 +92,7 @@ func (s *SnapshotStore) Create(state *State) (abci.Snapshot, error) { snapshot := abci.Snapshot{ Height: state.Height, Format: 1, - Hash: hashItems(state.Values), + Hash: hashItems(state.Values, state.Height), Chunks: byteChunks(bz), } err = os.WriteFile(filepath.Join(s.dir, fmt.Sprintf("%v.json", state.Height)), bz, 0644) diff --git a/test/e2e/app/state.go b/test/e2e/app/state.go index e82a22539..17d8cd75f 100644 --- a/test/e2e/app/state.go +++ b/test/e2e/app/state.go @@ -3,6 +3,7 @@ package app import ( "crypto/sha256" + "encoding/binary" "encoding/json" "errors" "fmt" @@ -38,7 +39,7 @@ func NewState(dir string, persistInterval uint64) (*State, error) { previousFile: filepath.Join(dir, prevStateFileName), persistInterval: persistInterval, } - state.Hash = hashItems(state.Values) + state.Hash = hashItems(state.Values, state.Height) err := state.load() switch { case errors.Is(err, os.ErrNotExist): @@ -114,7 +115,7 @@ func (s *State) Import(height uint64, jsonBytes []byte) error { } s.Height = height s.Values = values - s.Hash = hashItems(values) + s.Hash = hashItems(values, height) return s.save() } @@ -140,7 +141,6 @@ func (s *State) Set(key, value string) { func (s *State) Commit() (uint64, []byte, error) { s.Lock() defer s.Unlock() - s.Hash = hashItems(s.Values) switch { case s.Height > 0: s.Height++ @@ -149,6 +149,7 @@ func (s *State) Commit() (uint64, []byte, error) { default: s.Height = 1 } + s.Hash = hashItems(s.Values, s.Height) if s.persistInterval > 0 && s.Height%s.persistInterval == 0 { err := s.save() if err != nil { @@ -171,7 +172,7 @@ func (s *State) Rollback() error { } // hashItems hashes a set of key/value items. -func hashItems(items map[string]string) []byte { +func hashItems(items map[string]string, height uint64) []byte { keys := make([]string, 0, len(items)) for key := range items { keys = append(keys, key) @@ -179,6 +180,9 @@ func hashItems(items map[string]string) []byte { sort.Strings(keys) hasher := sha256.New() + var b [8]byte + binary.BigEndian.PutUint64(b[:], height) + _, _ = hasher.Write(b[:]) for _, key := range keys { _, _ = hasher.Write([]byte(key)) _, _ = hasher.Write([]byte{0}) diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 7234a5cde..36115346b 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -48,23 +48,24 @@ func TestApp_Hash(t *testing.T) { info, err := client.ABCIInfo(ctx) require.NoError(t, err) require.NotEmpty(t, info.Response.LastBlockAppHash, "expected app to return app hash") + // In next-block execution, the app hash is stored in the next block + blockHeight := info.Response.LastBlockHeight + 1 - status, err := client.Status(ctx) - require.NoError(t, err) - require.NotZero(t, status.SyncInfo.LatestBlockHeight) + require.Eventually(t, func() bool { + status, err := client.Status(ctx) + require.NoError(t, err) + require.NotZero(t, status.SyncInfo.LatestBlockHeight) + return status.SyncInfo.LatestBlockHeight >= blockHeight + }, 60*time.Second, 500*time.Millisecond) - block, err := client.Block(ctx, &info.Response.LastBlockHeight) + block, err := client.Block(ctx, &blockHeight) require.NoError(t, err) - if info.Response.LastBlockHeight == block.Block.Height { - require.Equal(t, - fmt.Sprintf("%x", info.Response.LastBlockAppHash), - fmt.Sprintf("%x", block.Block.AppHash.Bytes()), - "app hash does not match last block's app hash") - } - - require.True(t, status.SyncInfo.LatestBlockHeight >= info.Response.LastBlockHeight, - "status out of sync with application") + require.Equal(t, blockHeight, block.Block.Height) + require.Equal(t, + fmt.Sprintf("%x", info.Response.LastBlockAppHash), + fmt.Sprintf("%x", block.Block.AppHash.Bytes()), + "app hash does not match last block's app hash") }) } From 99f9ee0f63627462e4daa3e785ec23086aa3a0b5 Mon Sep 17 00:00:00 2001 From: William Banfield <4561443+williambanfield@users.noreply.github.com> Date: Fri, 1 Apr 2022 17:44:38 -0400 Subject: [PATCH 08/20] abci++: correct max-size check to only operate on added and unmodified (#8242) --- types/tx.go | 14 ++++++++------ types/tx_test.go | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/types/tx.go b/types/tx.go index b81114452..0c354a941 100644 --- a/types/tx.go +++ b/types/tx.go @@ -188,13 +188,7 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { // Only the slices are copied, the transaction contents are shared. allCopy := sortedCopy(t.all) - var size int64 for i, cur := range allCopy { - size += int64(len(cur)) - if size > maxSizeBytes { - return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes) - } - // allCopy is sorted, so any duplicated data will be adjacent. if i+1 < len(allCopy) && bytes.Equal(cur, allCopy[i+1]) { return fmt.Errorf("found duplicate transaction with hash: %x", cur.Hash()) @@ -207,6 +201,14 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { removedCopy := sortedCopy(t.removed) unmodifiedCopy := sortedCopy(t.unmodified) + var size int64 + for _, cur := range append(unmodifiedCopy, addedCopy...) { + size += int64(len(cur)) + if size > maxSizeBytes { + return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes) + } + } + // make a defensive copy of otxs so that the order of // the caller's data is not altered. otxsCopy := sortedCopy(otxs) diff --git a/types/tx_test.go b/types/tx_test.go index d8737e9f0..77afa1b23 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -64,6 +64,25 @@ func TestValidateTxRecordSet(t *testing.T) { err := txrSet.Validate(9, []Tx{}) require.Error(t, err) }) + t.Run("should not error on removed transaction size exceeding max data size", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{6, 7, 8, 9}), + }, + { + Action: abci.TxRecord_REMOVED, + Tx: Tx([]byte{10}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(9, []Tx{[]byte{10}}) + require.NoError(t, err) + }) t.Run("should error on duplicate transactions with the same action", func(t *testing.T) { trs := []*abci.TxRecord{ { From 9fe25a1ed101a4fe7d62ce2d4e2a196ff5841a5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 11:49:00 +0200 Subject: [PATCH 09/20] build(deps): Bump bufbuild/buf-setup-action from 1.3.0 to 1.3.1 (#8245) --- .github/workflows/proto-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/proto-lint.yml b/.github/workflows/proto-lint.yml index 2d4052f90..8d0da6798 100644 --- a/.github/workflows/proto-lint.yml +++ b/.github/workflows/proto-lint.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v3 - - uses: bufbuild/buf-setup-action@v1.3.0 + - uses: bufbuild/buf-setup-action@v1.3.1 - uses: bufbuild/buf-lint-action@v1 with: input: 'proto' From 8df38db82e3641cff6ece710fc5bc422b8feff41 Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Mon, 4 Apr 2022 12:43:01 +0200 Subject: [PATCH 10/20] Remove `ModifiedTxStatus` from the spec and the code (#8210) * Outstanding abci-gen changes to 'pb.go' files * Removed modified_tx_status from spec and protobufs * Fix sed for OSX * Regenerated abci protobufs with 'abci-proto-gen' * Code changes. UTs e2e tests passing * Recovered UT: TestPrepareProposalModifiedTxStatusFalse * Adapted UT * Fixed UT * Revert "Fix sed for OSX" This reverts commit e576708c618f0ef732498f4d348503b823b6c9e8. * Update internal/state/execution_test.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update abci/example/kvstore/kvstore.go Co-authored-by: M. J. Fromberger * Update internal/state/execution_test.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update spec/abci++/abci++_tmint_expected_behavior_002_draft.md Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Addressed some comments * Added one test that tests error at the ABCI client + Fixed some mock calls * Addressed remaining comments * Update abci/example/kvstore/kvstore.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update abci/example/kvstore/kvstore.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update abci/example/kvstore/kvstore.go Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Update spec/abci++/abci++_tmint_expected_behavior_002_draft.md Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> * Addressed William's latest comments * Adressed Michael's comment * Fixed UT * Some md fixes * More md fixes * gofmt Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> Co-authored-by: M. J. Fromberger --- abci/client/mocks/client.go | 1 + abci/example/kvstore/kvstore.go | 31 +- abci/types/application.go | 14 +- abci/types/mocks/application.go | 1 + abci/types/types.go | 8 - abci/types/types.pb.go | 1974 ++++++++--------- cmd/tendermint/commands/debug/debug.go | 1 + internal/consensus/mempool_test.go | 15 +- internal/consensus/mocks/cons_sync_reactor.go | 1 + internal/consensus/peer_state_test.go | 1 + internal/consensus/state.go | 6 +- internal/evidence/mocks/block_store.go | 1 + internal/mempool/mempool_bench_test.go | 1 + internal/proxy/client.go | 1 + internal/proxy/client_test.go | 3 +- internal/state/execution.go | 17 +- internal/state/execution_test.go | 129 +- internal/state/helpers_test.go | 2 +- internal/state/indexer/mocks/event_sink.go | 1 + internal/state/mocks/evidence_pool.go | 1 + internal/state/mocks/store.go | 1 + internal/state/test/factory/block.go | 2 +- internal/state/validation_test.go | 2 +- internal/statesync/mocks/state_provider.go | 1 + internal/test/factory/tx.go | 6 +- proto/tendermint/abci/types.proto | 17 +- .../tendermint/abci/types.proto.intermediate | 17 +- spec/abci++/abci++_methods_002_draft.md | 48 +- ...bci++_tmint_expected_behavior_002_draft.md | 23 +- test/e2e/app/app.go | 14 +- types/tx.go | 2 +- 31 files changed, 1163 insertions(+), 1179 deletions(-) diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index 37df53979..7743e5897 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -6,6 +6,7 @@ import ( context "context" mock "github.com/stretchr/testify/mock" + types "github.com/tendermint/tendermint/abci/types" ) diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index 40f45d459..0563cd7e6 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -285,8 +285,7 @@ func (app *Application) PrepareProposal(req types.RequestPrepareProposal) types. defer app.mu.Unlock() return types.ResponsePrepareProposal{ - ModifiedTxStatus: types.ResponsePrepareProposal_MODIFIED, - TxRecords: app.substPrepareTx(req.Txs), + TxRecords: app.substPrepareTx(req.Txs, req.MaxTxBytes), } } @@ -434,28 +433,32 @@ func (app *Application) execPrepareTx(tx []byte) *types.ExecTxResult { } // substPrepareTx substitutes all the transactions prefixed with 'prepare' in the -// proposal for transactions with the prefix strips. +// proposal for transactions with the prefix stripped. // It marks all of the original transactions as 'REMOVED' so that // Tendermint will remove them from its mempool. -func (app *Application) substPrepareTx(blockData [][]byte) []*types.TxRecord { - trs := make([]*types.TxRecord, len(blockData)) +func (app *Application) substPrepareTx(blockData [][]byte, maxTxBytes int64) []*types.TxRecord { + trs := make([]*types.TxRecord, 0, len(blockData)) var removed []*types.TxRecord - for i, tx := range blockData { + var totalBytes int64 + for _, tx := range blockData { + txMod := tx + action := types.TxRecord_UNMODIFIED if isPrepareTx(tx) { removed = append(removed, &types.TxRecord{ Tx: tx, Action: types.TxRecord_REMOVED, }) - trs[i] = &types.TxRecord{ - Tx: bytes.TrimPrefix(tx, []byte(PreparePrefix)), - Action: types.TxRecord_ADDED, - } - continue + txMod = bytes.TrimPrefix(tx, []byte(PreparePrefix)) + action = types.TxRecord_ADDED } - trs[i] = &types.TxRecord{ - Tx: tx, - Action: types.TxRecord_UNMODIFIED, + totalBytes += int64(len(txMod)) + if totalBytes > maxTxBytes { + break } + trs = append(trs, &types.TxRecord{ + Tx: txMod, + Action: action, + }) } return append(trs, removed...) diff --git a/abci/types/application.go b/abci/types/application.go index 8b8991adc..959311e3b 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -95,7 +95,19 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons } func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { - return ResponsePrepareProposal{ModifiedTxStatus: ResponsePrepareProposal_UNMODIFIED} + trs := make([]*TxRecord, 0, len(req.Txs)) + var totalBytes int64 + for _, tx := range req.Txs { + totalBytes += int64(len(tx)) + if totalBytes > req.MaxTxBytes { + break + } + trs = append(trs, &TxRecord{ + Action: TxRecord_UNMODIFIED, + Tx: tx, + }) + } + return ResponsePrepareProposal{TxRecords: trs} } func (BaseApplication) ProcessProposal(req RequestProcessProposal) ResponseProcessProposal { diff --git a/abci/types/mocks/application.go b/abci/types/mocks/application.go index 30bf0f84c..45e2f1c45 100644 --- a/abci/types/mocks/application.go +++ b/abci/types/mocks/application.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + types "github.com/tendermint/tendermint/abci/types" ) diff --git a/abci/types/types.go b/abci/types/types.go index 3955e7af0..d74a2289a 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -53,14 +53,6 @@ func (r ResponseQuery) IsErr() bool { return r.Code != CodeTypeOK } -func (r ResponsePrepareProposal) IsTxStatusUnknown() bool { - return r.ModifiedTxStatus == ResponsePrepareProposal_UNKNOWN -} - -func (r ResponsePrepareProposal) IsTxStatusModified() bool { - return r.ModifiedTxStatus == ResponsePrepareProposal_MODIFIED -} - func (r ResponseProcessProposal) IsAccepted() bool { return r.Status == ResponseProcessProposal_ACCEPT } diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index cbea553af..cd3ced31f 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -160,62 +160,6 @@ func (ResponseApplySnapshotChunk_Result) EnumDescriptor() ([]byte, []int) { return fileDescriptor_252557cfdd89a31a, []int{35, 0} } -type ResponseVerifyVoteExtension_VerifyStatus int32 - -const ( - ResponseVerifyVoteExtension_UNKNOWN ResponseVerifyVoteExtension_VerifyStatus = 0 - ResponseVerifyVoteExtension_ACCEPT ResponseVerifyVoteExtension_VerifyStatus = 1 - ResponseVerifyVoteExtension_REJECT ResponseVerifyVoteExtension_VerifyStatus = 2 -) - -var ResponseVerifyVoteExtension_VerifyStatus_name = map[int32]string{ - 0: "UNKNOWN", - 1: "ACCEPT", - 2: "REJECT", -} - -var ResponseVerifyVoteExtension_VerifyStatus_value = map[string]int32{ - "UNKNOWN": 0, - "ACCEPT": 1, - "REJECT": 2, -} - -func (x ResponseVerifyVoteExtension_VerifyStatus) String() string { - return proto.EnumName(ResponseVerifyVoteExtension_VerifyStatus_name, int32(x)) -} - -func (ResponseVerifyVoteExtension_VerifyStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{37, 0} -} - -type ResponsePrepareProposal_ModifiedTxStatus int32 - -const ( - ResponsePrepareProposal_UNKNOWN ResponsePrepareProposal_ModifiedTxStatus = 0 - ResponsePrepareProposal_UNMODIFIED ResponsePrepareProposal_ModifiedTxStatus = 1 - ResponsePrepareProposal_MODIFIED ResponsePrepareProposal_ModifiedTxStatus = 2 -) - -var ResponsePrepareProposal_ModifiedTxStatus_name = map[int32]string{ - 0: "UNKNOWN", - 1: "UNMODIFIED", - 2: "MODIFIED", -} - -var ResponsePrepareProposal_ModifiedTxStatus_value = map[string]int32{ - "UNKNOWN": 0, - "UNMODIFIED": 1, - "MODIFIED": 2, -} - -func (x ResponsePrepareProposal_ModifiedTxStatus) String() string { - return proto.EnumName(ResponsePrepareProposal_ModifiedTxStatus_name, int32(x)) -} - -func (ResponsePrepareProposal_ModifiedTxStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{38, 0} -} - type ResponseProcessProposal_ProposalStatus int32 const ( @@ -241,6 +185,34 @@ func (x ResponseProcessProposal_ProposalStatus) String() string { } func (ResponseProcessProposal_ProposalStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{37, 0} +} + +type ResponseVerifyVoteExtension_VerifyStatus int32 + +const ( + ResponseVerifyVoteExtension_UNKNOWN ResponseVerifyVoteExtension_VerifyStatus = 0 + ResponseVerifyVoteExtension_ACCEPT ResponseVerifyVoteExtension_VerifyStatus = 1 + ResponseVerifyVoteExtension_REJECT ResponseVerifyVoteExtension_VerifyStatus = 2 +) + +var ResponseVerifyVoteExtension_VerifyStatus_name = map[int32]string{ + 0: "UNKNOWN", + 1: "ACCEPT", + 2: "REJECT", +} + +var ResponseVerifyVoteExtension_VerifyStatus_value = map[string]int32{ + "UNKNOWN": 0, + "ACCEPT": 1, + "REJECT": 2, +} + +func (x ResponseVerifyVoteExtension_VerifyStatus) String() string { + return proto.EnumName(ResponseVerifyVoteExtension_VerifyStatus_name, int32(x)) +} + +func (ResponseVerifyVoteExtension_VerifyStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor_252557cfdd89a31a, []int{39, 0} } @@ -1341,96 +1313,6 @@ func (m *RequestApplySnapshotChunk) GetSender() string { return "" } -// Extends a vote with application-side injection -type RequestExtendVote struct { - Vote *types1.Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"` -} - -func (m *RequestExtendVote) Reset() { *m = RequestExtendVote{} } -func (m *RequestExtendVote) String() string { return proto.CompactTextString(m) } -func (*RequestExtendVote) ProtoMessage() {} -func (*RequestExtendVote) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{15} -} -func (m *RequestExtendVote) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *RequestExtendVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_RequestExtendVote.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *RequestExtendVote) XXX_Merge(src proto.Message) { - xxx_messageInfo_RequestExtendVote.Merge(m, src) -} -func (m *RequestExtendVote) XXX_Size() int { - return m.Size() -} -func (m *RequestExtendVote) XXX_DiscardUnknown() { - xxx_messageInfo_RequestExtendVote.DiscardUnknown(m) -} - -var xxx_messageInfo_RequestExtendVote proto.InternalMessageInfo - -func (m *RequestExtendVote) GetVote() *types1.Vote { - if m != nil { - return m.Vote - } - return nil -} - -// Verify the vote extension -type RequestVerifyVoteExtension struct { - Vote *types1.Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"` -} - -func (m *RequestVerifyVoteExtension) Reset() { *m = RequestVerifyVoteExtension{} } -func (m *RequestVerifyVoteExtension) String() string { return proto.CompactTextString(m) } -func (*RequestVerifyVoteExtension) ProtoMessage() {} -func (*RequestVerifyVoteExtension) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{16} -} -func (m *RequestVerifyVoteExtension) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *RequestVerifyVoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_RequestVerifyVoteExtension.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *RequestVerifyVoteExtension) XXX_Merge(src proto.Message) { - xxx_messageInfo_RequestVerifyVoteExtension.Merge(m, src) -} -func (m *RequestVerifyVoteExtension) XXX_Size() int { - return m.Size() -} -func (m *RequestVerifyVoteExtension) XXX_DiscardUnknown() { - xxx_messageInfo_RequestVerifyVoteExtension.DiscardUnknown(m) -} - -var xxx_messageInfo_RequestVerifyVoteExtension proto.InternalMessageInfo - -func (m *RequestVerifyVoteExtension) GetVote() *types1.Vote { - if m != nil { - return m.Vote - } - return nil -} - type RequestPrepareProposal struct { Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` Header types1.Header `protobuf:"bytes,2,opt,name=header,proto3" json:"header"` @@ -1447,7 +1329,7 @@ func (m *RequestPrepareProposal) Reset() { *m = RequestPrepareProposal{} func (m *RequestPrepareProposal) String() string { return proto.CompactTextString(m) } func (*RequestPrepareProposal) ProtoMessage() {} func (*RequestPrepareProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{17} + return fileDescriptor_252557cfdd89a31a, []int{15} } func (m *RequestPrepareProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1530,7 +1412,7 @@ func (m *RequestProcessProposal) Reset() { *m = RequestProcessProposal{} func (m *RequestProcessProposal) String() string { return proto.CompactTextString(m) } func (*RequestProcessProposal) ProtoMessage() {} func (*RequestProcessProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{18} + return fileDescriptor_252557cfdd89a31a, []int{16} } func (m *RequestProcessProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1594,6 +1476,96 @@ func (m *RequestProcessProposal) GetByzantineValidators() []Evidence { return nil } +// Extends a vote with application-side injection +type RequestExtendVote struct { + Vote *types1.Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"` +} + +func (m *RequestExtendVote) Reset() { *m = RequestExtendVote{} } +func (m *RequestExtendVote) String() string { return proto.CompactTextString(m) } +func (*RequestExtendVote) ProtoMessage() {} +func (*RequestExtendVote) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{17} +} +func (m *RequestExtendVote) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RequestExtendVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RequestExtendVote.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RequestExtendVote) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestExtendVote.Merge(m, src) +} +func (m *RequestExtendVote) XXX_Size() int { + return m.Size() +} +func (m *RequestExtendVote) XXX_DiscardUnknown() { + xxx_messageInfo_RequestExtendVote.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestExtendVote proto.InternalMessageInfo + +func (m *RequestExtendVote) GetVote() *types1.Vote { + if m != nil { + return m.Vote + } + return nil +} + +// Verify the vote extension +type RequestVerifyVoteExtension struct { + Vote *types1.Vote `protobuf:"bytes,1,opt,name=vote,proto3" json:"vote,omitempty"` +} + +func (m *RequestVerifyVoteExtension) Reset() { *m = RequestVerifyVoteExtension{} } +func (m *RequestVerifyVoteExtension) String() string { return proto.CompactTextString(m) } +func (*RequestVerifyVoteExtension) ProtoMessage() {} +func (*RequestVerifyVoteExtension) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{18} +} +func (m *RequestVerifyVoteExtension) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RequestVerifyVoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RequestVerifyVoteExtension.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RequestVerifyVoteExtension) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestVerifyVoteExtension.Merge(m, src) +} +func (m *RequestVerifyVoteExtension) XXX_Size() int { + return m.Size() +} +func (m *RequestVerifyVoteExtension) XXX_DiscardUnknown() { + xxx_messageInfo_RequestVerifyVoteExtension.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestVerifyVoteExtension proto.InternalMessageInfo + +func (m *RequestVerifyVoteExtension) GetVote() *types1.Vote { + if m != nil { + return m.Vote + } + return nil +} + type RequestFinalizeBlock struct { Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` Header types1.Header `protobuf:"bytes,2,opt,name=header,proto3" json:"header"` @@ -2937,108 +2909,19 @@ func (m *ResponseApplySnapshotChunk) GetRejectSenders() []string { return nil } -type ResponseExtendVote struct { - VoteExtension *types1.VoteExtension `protobuf:"bytes,1,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` -} - -func (m *ResponseExtendVote) Reset() { *m = ResponseExtendVote{} } -func (m *ResponseExtendVote) String() string { return proto.CompactTextString(m) } -func (*ResponseExtendVote) ProtoMessage() {} -func (*ResponseExtendVote) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{36} -} -func (m *ResponseExtendVote) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ResponseExtendVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ResponseExtendVote.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ResponseExtendVote) XXX_Merge(src proto.Message) { - xxx_messageInfo_ResponseExtendVote.Merge(m, src) -} -func (m *ResponseExtendVote) XXX_Size() int { - return m.Size() -} -func (m *ResponseExtendVote) XXX_DiscardUnknown() { - xxx_messageInfo_ResponseExtendVote.DiscardUnknown(m) -} - -var xxx_messageInfo_ResponseExtendVote proto.InternalMessageInfo - -func (m *ResponseExtendVote) GetVoteExtension() *types1.VoteExtension { - if m != nil { - return m.VoteExtension - } - return nil -} - -type ResponseVerifyVoteExtension struct { - Status ResponseVerifyVoteExtension_VerifyStatus `protobuf:"varint,1,opt,name=status,proto3,enum=tendermint.abci.ResponseVerifyVoteExtension_VerifyStatus" json:"status,omitempty"` -} - -func (m *ResponseVerifyVoteExtension) Reset() { *m = ResponseVerifyVoteExtension{} } -func (m *ResponseVerifyVoteExtension) String() string { return proto.CompactTextString(m) } -func (*ResponseVerifyVoteExtension) ProtoMessage() {} -func (*ResponseVerifyVoteExtension) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{37} -} -func (m *ResponseVerifyVoteExtension) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ResponseVerifyVoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ResponseVerifyVoteExtension.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ResponseVerifyVoteExtension) XXX_Merge(src proto.Message) { - xxx_messageInfo_ResponseVerifyVoteExtension.Merge(m, src) -} -func (m *ResponseVerifyVoteExtension) XXX_Size() int { - return m.Size() -} -func (m *ResponseVerifyVoteExtension) XXX_DiscardUnknown() { - xxx_messageInfo_ResponseVerifyVoteExtension.DiscardUnknown(m) -} - -var xxx_messageInfo_ResponseVerifyVoteExtension proto.InternalMessageInfo - -func (m *ResponseVerifyVoteExtension) GetStatus() ResponseVerifyVoteExtension_VerifyStatus { - if m != nil { - return m.Status - } - return ResponseVerifyVoteExtension_UNKNOWN -} - type ResponsePrepareProposal struct { - ModifiedTxStatus ResponsePrepareProposal_ModifiedTxStatus `protobuf:"varint,1,opt,name=modified_tx_status,json=modifiedTxStatus,proto3,enum=tendermint.abci.ResponsePrepareProposal_ModifiedTxStatus" json:"modified_tx_status,omitempty"` - TxRecords []*TxRecord `protobuf:"bytes,2,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` - AppHash []byte `protobuf:"bytes,3,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"` - TxResults []*ExecTxResult `protobuf:"bytes,4,rep,name=tx_results,json=txResults,proto3" json:"tx_results,omitempty"` - ValidatorUpdates []*ValidatorUpdate `protobuf:"bytes,5,rep,name=validator_updates,json=validatorUpdates,proto3" json:"validator_updates,omitempty"` - ConsensusParamUpdates *types1.ConsensusParams `protobuf:"bytes,6,opt,name=consensus_param_updates,json=consensusParamUpdates,proto3" json:"consensus_param_updates,omitempty"` + TxRecords []*TxRecord `protobuf:"bytes,1,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` + AppHash []byte `protobuf:"bytes,2,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"` + TxResults []*ExecTxResult `protobuf:"bytes,3,rep,name=tx_results,json=txResults,proto3" json:"tx_results,omitempty"` + ValidatorUpdates []*ValidatorUpdate `protobuf:"bytes,4,rep,name=validator_updates,json=validatorUpdates,proto3" json:"validator_updates,omitempty"` + ConsensusParamUpdates *types1.ConsensusParams `protobuf:"bytes,5,opt,name=consensus_param_updates,json=consensusParamUpdates,proto3" json:"consensus_param_updates,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } func (m *ResponsePrepareProposal) String() string { return proto.CompactTextString(m) } func (*ResponsePrepareProposal) ProtoMessage() {} func (*ResponsePrepareProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{38} + return fileDescriptor_252557cfdd89a31a, []int{36} } func (m *ResponsePrepareProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3067,13 +2950,6 @@ func (m *ResponsePrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ResponsePrepareProposal proto.InternalMessageInfo -func (m *ResponsePrepareProposal) GetModifiedTxStatus() ResponsePrepareProposal_ModifiedTxStatus { - if m != nil { - return m.ModifiedTxStatus - } - return ResponsePrepareProposal_UNKNOWN -} - func (m *ResponsePrepareProposal) GetTxRecords() []*TxRecord { if m != nil { return m.TxRecords @@ -3121,7 +2997,7 @@ func (m *ResponseProcessProposal) Reset() { *m = ResponseProcessProposal func (m *ResponseProcessProposal) String() string { return proto.CompactTextString(m) } func (*ResponseProcessProposal) ProtoMessage() {} func (*ResponseProcessProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{39} + return fileDescriptor_252557cfdd89a31a, []int{37} } func (m *ResponseProcessProposal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3185,6 +3061,94 @@ func (m *ResponseProcessProposal) GetConsensusParamUpdates() *types1.ConsensusPa return nil } +type ResponseExtendVote struct { + VoteExtension *types1.VoteExtension `protobuf:"bytes,1,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` +} + +func (m *ResponseExtendVote) Reset() { *m = ResponseExtendVote{} } +func (m *ResponseExtendVote) String() string { return proto.CompactTextString(m) } +func (*ResponseExtendVote) ProtoMessage() {} +func (*ResponseExtendVote) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{38} +} +func (m *ResponseExtendVote) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResponseExtendVote) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResponseExtendVote.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResponseExtendVote) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseExtendVote.Merge(m, src) +} +func (m *ResponseExtendVote) XXX_Size() int { + return m.Size() +} +func (m *ResponseExtendVote) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseExtendVote.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseExtendVote proto.InternalMessageInfo + +func (m *ResponseExtendVote) GetVoteExtension() *types1.VoteExtension { + if m != nil { + return m.VoteExtension + } + return nil +} + +type ResponseVerifyVoteExtension struct { + Status ResponseVerifyVoteExtension_VerifyStatus `protobuf:"varint,1,opt,name=status,proto3,enum=tendermint.abci.ResponseVerifyVoteExtension_VerifyStatus" json:"status,omitempty"` +} + +func (m *ResponseVerifyVoteExtension) Reset() { *m = ResponseVerifyVoteExtension{} } +func (m *ResponseVerifyVoteExtension) String() string { return proto.CompactTextString(m) } +func (*ResponseVerifyVoteExtension) ProtoMessage() {} +func (*ResponseVerifyVoteExtension) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{39} +} +func (m *ResponseVerifyVoteExtension) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResponseVerifyVoteExtension) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResponseVerifyVoteExtension.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResponseVerifyVoteExtension) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseVerifyVoteExtension.Merge(m, src) +} +func (m *ResponseVerifyVoteExtension) XXX_Size() int { + return m.Size() +} +func (m *ResponseVerifyVoteExtension) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseVerifyVoteExtension.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseVerifyVoteExtension proto.InternalMessageInfo + +func (m *ResponseVerifyVoteExtension) GetStatus() ResponseVerifyVoteExtension_VerifyStatus { + if m != nil { + return m.Status + } + return ResponseVerifyVoteExtension_UNKNOWN +} + type ResponseFinalizeBlock struct { Events []Event `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` TxResults []*ExecTxResult `protobuf:"bytes,2,rep,name=tx_results,json=txResults,proto3" json:"tx_results,omitempty"` @@ -4098,9 +4062,8 @@ func init() { proto.RegisterEnum("tendermint.abci.EvidenceType", EvidenceType_name, EvidenceType_value) proto.RegisterEnum("tendermint.abci.ResponseOfferSnapshot_Result", ResponseOfferSnapshot_Result_name, ResponseOfferSnapshot_Result_value) proto.RegisterEnum("tendermint.abci.ResponseApplySnapshotChunk_Result", ResponseApplySnapshotChunk_Result_name, ResponseApplySnapshotChunk_Result_value) - proto.RegisterEnum("tendermint.abci.ResponseVerifyVoteExtension_VerifyStatus", ResponseVerifyVoteExtension_VerifyStatus_name, ResponseVerifyVoteExtension_VerifyStatus_value) - proto.RegisterEnum("tendermint.abci.ResponsePrepareProposal_ModifiedTxStatus", ResponsePrepareProposal_ModifiedTxStatus_name, ResponsePrepareProposal_ModifiedTxStatus_value) proto.RegisterEnum("tendermint.abci.ResponseProcessProposal_ProposalStatus", ResponseProcessProposal_ProposalStatus_name, ResponseProcessProposal_ProposalStatus_value) + proto.RegisterEnum("tendermint.abci.ResponseVerifyVoteExtension_VerifyStatus", ResponseVerifyVoteExtension_VerifyStatus_name, ResponseVerifyVoteExtension_VerifyStatus_value) proto.RegisterEnum("tendermint.abci.TxRecord_TxAction", TxRecord_TxAction_name, TxRecord_TxAction_value) proto.RegisterType((*Request)(nil), "tendermint.abci.Request") proto.RegisterType((*RequestEcho)(nil), "tendermint.abci.RequestEcho") @@ -4117,10 +4080,10 @@ func init() { proto.RegisterType((*RequestOfferSnapshot)(nil), "tendermint.abci.RequestOfferSnapshot") proto.RegisterType((*RequestLoadSnapshotChunk)(nil), "tendermint.abci.RequestLoadSnapshotChunk") proto.RegisterType((*RequestApplySnapshotChunk)(nil), "tendermint.abci.RequestApplySnapshotChunk") - proto.RegisterType((*RequestExtendVote)(nil), "tendermint.abci.RequestExtendVote") - proto.RegisterType((*RequestVerifyVoteExtension)(nil), "tendermint.abci.RequestVerifyVoteExtension") proto.RegisterType((*RequestPrepareProposal)(nil), "tendermint.abci.RequestPrepareProposal") proto.RegisterType((*RequestProcessProposal)(nil), "tendermint.abci.RequestProcessProposal") + proto.RegisterType((*RequestExtendVote)(nil), "tendermint.abci.RequestExtendVote") + proto.RegisterType((*RequestVerifyVoteExtension)(nil), "tendermint.abci.RequestVerifyVoteExtension") proto.RegisterType((*RequestFinalizeBlock)(nil), "tendermint.abci.RequestFinalizeBlock") proto.RegisterType((*Response)(nil), "tendermint.abci.Response") proto.RegisterType((*ResponseException)(nil), "tendermint.abci.ResponseException") @@ -4138,10 +4101,10 @@ func init() { proto.RegisterType((*ResponseOfferSnapshot)(nil), "tendermint.abci.ResponseOfferSnapshot") proto.RegisterType((*ResponseLoadSnapshotChunk)(nil), "tendermint.abci.ResponseLoadSnapshotChunk") proto.RegisterType((*ResponseApplySnapshotChunk)(nil), "tendermint.abci.ResponseApplySnapshotChunk") - proto.RegisterType((*ResponseExtendVote)(nil), "tendermint.abci.ResponseExtendVote") - proto.RegisterType((*ResponseVerifyVoteExtension)(nil), "tendermint.abci.ResponseVerifyVoteExtension") proto.RegisterType((*ResponsePrepareProposal)(nil), "tendermint.abci.ResponsePrepareProposal") proto.RegisterType((*ResponseProcessProposal)(nil), "tendermint.abci.ResponseProcessProposal") + proto.RegisterType((*ResponseExtendVote)(nil), "tendermint.abci.ResponseExtendVote") + proto.RegisterType((*ResponseVerifyVoteExtension)(nil), "tendermint.abci.ResponseVerifyVoteExtension") proto.RegisterType((*ResponseFinalizeBlock)(nil), "tendermint.abci.ResponseFinalizeBlock") proto.RegisterType((*CommitInfo)(nil), "tendermint.abci.CommitInfo") proto.RegisterType((*ExtendedCommitInfo)(nil), "tendermint.abci.ExtendedCommitInfo") @@ -4161,223 +4124,219 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3443 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5b, 0xcb, 0x73, 0x1b, 0xc7, - 0xd1, 0xc7, 0xfb, 0xd1, 0x78, 0x2d, 0x87, 0xb4, 0x0c, 0xc1, 0x12, 0x29, 0xaf, 0xca, 0xb6, 0x2c, - 0xdb, 0xd4, 0x67, 0xa9, 0x64, 0xcb, 0x9f, 0xed, 0xcf, 0x45, 0x82, 0xa0, 0x41, 0x89, 0x22, 0xe9, - 0x25, 0x28, 0x97, 0xbf, 0xcf, 0x9f, 0xd6, 0x4b, 0xec, 0x10, 0x58, 0x0b, 0xc0, 0xae, 0x77, 0x17, - 0x34, 0xe8, 0x53, 0x2a, 0x55, 0xbe, 0xb8, 0x52, 0x15, 0xdf, 0x92, 0xaa, 0x94, 0x2b, 0x97, 0xa4, - 0x2a, 0x7f, 0x42, 0x4e, 0xb9, 0x24, 0x07, 0x1f, 0x72, 0xf0, 0x2d, 0xa9, 0x1c, 0x9c, 0x94, 0x7d, - 0xcb, 0x3f, 0x90, 0x53, 0x9c, 0xd4, 0x3c, 0xf6, 0x09, 0x2c, 0x1e, 0x96, 0xe4, 0x4b, 0x6e, 0x33, - 0x8d, 0xee, 0xde, 0x99, 0x9e, 0x99, 0xee, 0xfe, 0xf5, 0x0c, 0xe0, 0x29, 0x1b, 0x0f, 0x54, 0x6c, - 0xf6, 0xb5, 0x81, 0x7d, 0x4d, 0x39, 0x6e, 0x6b, 0xd7, 0xec, 0x33, 0x03, 0x5b, 0xeb, 0x86, 0xa9, - 0xdb, 0x3a, 0xaa, 0x78, 0x3f, 0xae, 0x93, 0x1f, 0x6b, 0x17, 0x7d, 0xdc, 0x6d, 0xf3, 0xcc, 0xb0, - 0xf5, 0x6b, 0x86, 0xa9, 0xeb, 0x27, 0x8c, 0xbf, 0x76, 0xc1, 0xf7, 0x33, 0xd5, 0xe3, 0xd7, 0x16, - 0xf8, 0x95, 0x0b, 0x3f, 0xc0, 0x67, 0xce, 0xaf, 0x17, 0xc7, 0x64, 0x0d, 0xc5, 0x54, 0xfa, 0xce, - 0xcf, 0x6b, 0x1d, 0x5d, 0xef, 0xf4, 0xf0, 0x35, 0xda, 0x3b, 0x1e, 0x9e, 0x5c, 0xb3, 0xb5, 0x3e, - 0xb6, 0x6c, 0xa5, 0x6f, 0x70, 0x86, 0x95, 0x8e, 0xde, 0xd1, 0x69, 0xf3, 0x1a, 0x69, 0x31, 0xaa, - 0xf8, 0x2f, 0x80, 0xac, 0x84, 0x3f, 0x1a, 0x62, 0xcb, 0x46, 0xd7, 0x21, 0x85, 0xdb, 0x5d, 0xbd, - 0x1a, 0xbf, 0x14, 0xbf, 0x52, 0xb8, 0x7e, 0x61, 0x3d, 0x34, 0xb9, 0x75, 0xce, 0xd7, 0x68, 0x77, - 0xf5, 0x66, 0x4c, 0xa2, 0xbc, 0xe8, 0x26, 0xa4, 0x4f, 0x7a, 0x43, 0xab, 0x5b, 0x4d, 0x50, 0xa1, - 0x8b, 0x51, 0x42, 0xdb, 0x84, 0xa9, 0x19, 0x93, 0x18, 0x37, 0xf9, 0x94, 0x36, 0x38, 0xd1, 0xab, - 0xc9, 0xe9, 0x9f, 0xda, 0x19, 0x9c, 0xd0, 0x4f, 0x11, 0x5e, 0xb4, 0x09, 0xa0, 0x0d, 0x34, 0x5b, - 0x6e, 0x77, 0x15, 0x6d, 0x50, 0x4d, 0x51, 0xc9, 0xa7, 0xa3, 0x25, 0x35, 0xbb, 0x4e, 0x18, 0x9b, - 0x31, 0x29, 0xaf, 0x39, 0x1d, 0x32, 0xdc, 0x8f, 0x86, 0xd8, 0x3c, 0xab, 0xa6, 0xa7, 0x0f, 0xf7, - 0x1d, 0xc2, 0x44, 0x86, 0x4b, 0xb9, 0xd1, 0x0e, 0x14, 0x8e, 0x71, 0x47, 0x1b, 0xc8, 0xc7, 0x3d, - 0xbd, 0xfd, 0xa0, 0x9a, 0xa1, 0xc2, 0x62, 0x94, 0xf0, 0x26, 0x61, 0xdd, 0x24, 0x9c, 0x9b, 0x89, - 0x6a, 0xbc, 0x19, 0x93, 0xe0, 0xd8, 0xa5, 0xa0, 0x37, 0x20, 0xd7, 0xee, 0xe2, 0xf6, 0x03, 0xd9, - 0x1e, 0x55, 0xb3, 0x54, 0xcf, 0x5a, 0x94, 0x9e, 0x3a, 0xe1, 0x6b, 0x8d, 0x9a, 0x31, 0x29, 0xdb, - 0x66, 0x4d, 0xb4, 0x0d, 0xa0, 0xe2, 0x9e, 0x76, 0x8a, 0x4d, 0x22, 0x9f, 0x9b, 0x6e, 0x83, 0x2d, - 0xc6, 0xd9, 0x1a, 0xf1, 0x61, 0xe4, 0x55, 0x87, 0x80, 0xea, 0x90, 0xc7, 0x03, 0x95, 0x4f, 0x27, - 0x4f, 0xd5, 0x5c, 0x8a, 0x5c, 0xef, 0x81, 0xea, 0x9f, 0x4c, 0x0e, 0xf3, 0x3e, 0xba, 0x05, 0x99, - 0xb6, 0xde, 0xef, 0x6b, 0x76, 0x15, 0xa8, 0x86, 0xd5, 0xc8, 0x89, 0x50, 0xae, 0x66, 0x4c, 0xe2, - 0xfc, 0x68, 0x0f, 0xca, 0x3d, 0xcd, 0xb2, 0x65, 0x6b, 0xa0, 0x18, 0x56, 0x57, 0xb7, 0xad, 0x6a, - 0x81, 0x6a, 0x78, 0x26, 0x4a, 0xc3, 0xae, 0x66, 0xd9, 0x87, 0x0e, 0x73, 0x33, 0x26, 0x95, 0x7a, - 0x7e, 0x02, 0xd1, 0xa7, 0x9f, 0x9c, 0x60, 0xd3, 0x55, 0x58, 0x2d, 0x4e, 0xd7, 0xb7, 0x4f, 0xb8, - 0x1d, 0x79, 0xa2, 0x4f, 0xf7, 0x13, 0xd0, 0xff, 0xc1, 0x72, 0x4f, 0x57, 0x54, 0x57, 0x9d, 0xdc, - 0xee, 0x0e, 0x07, 0x0f, 0xaa, 0x25, 0xaa, 0xf4, 0xf9, 0xc8, 0x41, 0xea, 0x8a, 0xea, 0xa8, 0xa8, - 0x13, 0x81, 0x66, 0x4c, 0x5a, 0xea, 0x85, 0x89, 0xe8, 0x3e, 0xac, 0x28, 0x86, 0xd1, 0x3b, 0x0b, - 0x6b, 0x2f, 0x53, 0xed, 0x57, 0xa3, 0xb4, 0x6f, 0x10, 0x99, 0xb0, 0x7a, 0xa4, 0x8c, 0x51, 0x51, - 0x0b, 0x04, 0xc3, 0xc4, 0x86, 0x62, 0x62, 0xd9, 0x30, 0x75, 0x43, 0xb7, 0x94, 0x5e, 0xb5, 0x42, - 0x75, 0x3f, 0x17, 0xa5, 0xfb, 0x80, 0xf1, 0x1f, 0x70, 0xf6, 0x66, 0x4c, 0xaa, 0x18, 0x41, 0x12, - 0xd3, 0xaa, 0xb7, 0xb1, 0x65, 0x79, 0x5a, 0x85, 0x59, 0x5a, 0x29, 0x7f, 0x50, 0x6b, 0x80, 0x84, - 0x1a, 0x50, 0xc0, 0x23, 0x22, 0x2e, 0x9f, 0xea, 0x36, 0xae, 0x2e, 0x4d, 0x3f, 0x58, 0x0d, 0xca, - 0x7a, 0x4f, 0xb7, 0x31, 0x39, 0x54, 0xd8, 0xed, 0x21, 0x05, 0x9e, 0x38, 0xc5, 0xa6, 0x76, 0x72, - 0x46, 0xd5, 0xc8, 0xf4, 0x17, 0x4b, 0xd3, 0x07, 0x55, 0x44, 0x15, 0xbe, 0x10, 0xa5, 0xf0, 0x1e, - 0x15, 0x22, 0x2a, 0x1a, 0x8e, 0x48, 0x33, 0x26, 0x2d, 0x9f, 0x8e, 0x93, 0xc9, 0x16, 0x3b, 0xd1, - 0x06, 0x4a, 0x4f, 0xfb, 0x04, 0xf3, 0x63, 0xb3, 0x3c, 0x7d, 0x8b, 0x6d, 0x73, 0x6e, 0x7a, 0x56, - 0xc8, 0x16, 0x3b, 0xf1, 0x13, 0x36, 0xb3, 0x90, 0x3e, 0x55, 0x7a, 0x43, 0x2c, 0x3e, 0x07, 0x05, - 0x9f, 0x63, 0x45, 0x55, 0xc8, 0xf6, 0xb1, 0x65, 0x29, 0x1d, 0x4c, 0xfd, 0x70, 0x5e, 0x72, 0xba, - 0x62, 0x19, 0x8a, 0x7e, 0x67, 0x2a, 0x7e, 0x1e, 0x77, 0x25, 0x89, 0x9f, 0x24, 0x92, 0xa7, 0xd8, - 0xa4, 0xd3, 0xe6, 0x92, 0xbc, 0x8b, 0x2e, 0x43, 0x89, 0x0e, 0x59, 0x76, 0x7e, 0x27, 0xce, 0x3a, - 0x25, 0x15, 0x29, 0xf1, 0x1e, 0x67, 0x5a, 0x83, 0x82, 0x71, 0xdd, 0x70, 0x59, 0x92, 0x94, 0x05, - 0x8c, 0xeb, 0x86, 0xc3, 0xf0, 0x34, 0x14, 0xc9, 0xfc, 0x5c, 0x8e, 0x14, 0xfd, 0x48, 0x81, 0xd0, - 0x38, 0x8b, 0xf8, 0xc7, 0x04, 0x08, 0x61, 0x07, 0x8c, 0x6e, 0x41, 0x8a, 0xc4, 0x22, 0x1e, 0x56, - 0x6a, 0xeb, 0x2c, 0x50, 0xad, 0x3b, 0x81, 0x6a, 0xbd, 0xe5, 0x04, 0xaa, 0xcd, 0xdc, 0x97, 0x5f, - 0xaf, 0xc5, 0x3e, 0xff, 0xeb, 0x5a, 0x5c, 0xa2, 0x12, 0xe8, 0x3c, 0xf1, 0x95, 0x8a, 0x36, 0x90, - 0x35, 0x95, 0x0e, 0x39, 0x4f, 0x1c, 0xa1, 0xa2, 0x0d, 0x76, 0x54, 0xb4, 0x0b, 0x42, 0x5b, 0x1f, - 0x58, 0x78, 0x60, 0x0d, 0x2d, 0x99, 0x05, 0x42, 0x1e, 0x4c, 0x02, 0xee, 0x90, 0x85, 0xd7, 0xba, - 0xc3, 0x79, 0x40, 0x19, 0xa5, 0x4a, 0x3b, 0x48, 0x20, 0x6e, 0xf5, 0x54, 0xe9, 0x69, 0xaa, 0x62, - 0xeb, 0xa6, 0x55, 0x4d, 0x5d, 0x4a, 0x4e, 0xf4, 0x87, 0xf7, 0x1c, 0x96, 0x23, 0x43, 0x55, 0x6c, - 0xbc, 0x99, 0x22, 0xc3, 0x95, 0x7c, 0x92, 0xe8, 0x59, 0xa8, 0x28, 0x86, 0x21, 0x5b, 0xb6, 0x62, - 0x63, 0xf9, 0xf8, 0xcc, 0xc6, 0x16, 0x0d, 0x34, 0x45, 0xa9, 0xa4, 0x18, 0xc6, 0x21, 0xa1, 0x6e, - 0x12, 0x22, 0x7a, 0x06, 0xca, 0x24, 0x26, 0x69, 0x4a, 0x4f, 0xee, 0x62, 0xad, 0xd3, 0xb5, 0x69, - 0x48, 0x49, 0x4a, 0x25, 0x4e, 0x6d, 0x52, 0xa2, 0xa8, 0xba, 0x2b, 0x4e, 0xe3, 0x11, 0x42, 0x90, - 0x52, 0x15, 0x5b, 0xa1, 0x96, 0x2c, 0x4a, 0xb4, 0x4d, 0x68, 0x86, 0x62, 0x77, 0xb9, 0x7d, 0x68, - 0x1b, 0x9d, 0x83, 0x0c, 0x57, 0x9b, 0xa4, 0x6a, 0x79, 0x0f, 0xad, 0x40, 0xda, 0x30, 0xf5, 0x53, - 0x4c, 0x97, 0x2e, 0x27, 0xb1, 0x8e, 0xf8, 0xa3, 0x04, 0x2c, 0x8d, 0x45, 0x2e, 0xa2, 0xb7, 0xab, - 0x58, 0x5d, 0xe7, 0x5b, 0xa4, 0x8d, 0x5e, 0x21, 0x7a, 0x15, 0x15, 0x9b, 0x3c, 0xda, 0x57, 0xc7, - 0x4d, 0xdd, 0xa4, 0xbf, 0x73, 0xd3, 0x70, 0x6e, 0x74, 0x07, 0x84, 0x9e, 0x62, 0xd9, 0x32, 0xf3, - 0xfe, 0xb2, 0x2f, 0xf2, 0x3f, 0x35, 0x66, 0x64, 0x16, 0x2b, 0xc8, 0x86, 0xe6, 0x4a, 0xca, 0x44, - 0xd4, 0xa3, 0x22, 0x09, 0x56, 0x8e, 0xcf, 0x3e, 0x51, 0x06, 0xb6, 0x36, 0xc0, 0xf2, 0xd8, 0xaa, - 0x9d, 0x1f, 0x53, 0xd8, 0x38, 0xd5, 0x54, 0x3c, 0x68, 0x3b, 0xcb, 0xb5, 0xec, 0x0a, 0xbb, 0xcb, - 0x69, 0x89, 0x12, 0x94, 0x83, 0x31, 0x17, 0x95, 0x21, 0x61, 0x8f, 0xf8, 0xe4, 0x13, 0xf6, 0x08, - 0xfd, 0x17, 0xa4, 0xc8, 0x04, 0xe9, 0xc4, 0xcb, 0x13, 0x12, 0x16, 0x2e, 0xd7, 0x3a, 0x33, 0xb0, - 0x44, 0x39, 0x45, 0xd1, 0x3d, 0x0a, 0x6e, 0x1c, 0x0e, 0x6b, 0x15, 0x9f, 0x87, 0x4a, 0x28, 0xc8, - 0xfa, 0xd6, 0x2e, 0xee, 0x5f, 0x3b, 0xb1, 0x02, 0xa5, 0x40, 0x34, 0x15, 0xcf, 0xc1, 0xca, 0xa4, - 0xe0, 0x28, 0x76, 0x5d, 0x7a, 0x20, 0xc8, 0xa1, 0x9b, 0x90, 0x73, 0xa3, 0x23, 0x3b, 0x8a, 0xe3, - 0xb6, 0x72, 0x98, 0x25, 0x97, 0x95, 0x9c, 0x41, 0xb2, 0xa5, 0xe9, 0x5e, 0x48, 0xd0, 0x81, 0x67, - 0x15, 0xc3, 0x68, 0x2a, 0x56, 0x57, 0xfc, 0x00, 0xaa, 0x51, 0x91, 0x2f, 0x34, 0x8d, 0x94, 0xbb, - 0x05, 0xcf, 0x41, 0xe6, 0x44, 0x37, 0xfb, 0x8a, 0x4d, 0x95, 0x95, 0x24, 0xde, 0x23, 0x5b, 0x93, - 0x45, 0xc1, 0x24, 0x25, 0xb3, 0x8e, 0x28, 0xc3, 0xf9, 0xc8, 0xe8, 0x47, 0x44, 0xb4, 0x81, 0x8a, - 0x99, 0x3d, 0x4b, 0x12, 0xeb, 0x78, 0x8a, 0xd8, 0x60, 0x59, 0x87, 0x7c, 0xd6, 0xa2, 0x73, 0xa5, - 0xfa, 0xf3, 0x12, 0xef, 0x89, 0x6f, 0xb9, 0x5b, 0xdf, 0x8b, 0x2d, 0xe8, 0x2a, 0xa4, 0x68, 0x34, - 0x62, 0x56, 0x3a, 0x37, 0xbe, 0xc9, 0x09, 0x97, 0x44, 0x79, 0xc4, 0x26, 0xd4, 0xa2, 0x63, 0xc9, - 0x42, 0x9a, 0x7e, 0x9f, 0x80, 0x73, 0x93, 0xc3, 0xf1, 0x23, 0x3d, 0x8b, 0x02, 0x24, 0xed, 0x11, - 0xf1, 0x95, 0xc9, 0x2b, 0x45, 0x89, 0x34, 0xd1, 0x11, 0x2c, 0xf5, 0xf4, 0xb6, 0xd2, 0x93, 0x7d, - 0x67, 0x94, 0xa7, 0xd7, 0x97, 0xc7, 0x4f, 0x13, 0x35, 0x13, 0x56, 0xc7, 0x8e, 0x69, 0x85, 0xea, - 0xd8, 0x75, 0xcf, 0x6a, 0xe4, 0x39, 0x4d, 0x7f, 0xff, 0x73, 0x8a, 0x2e, 0x41, 0xb1, 0xaf, 0x8c, - 0x64, 0x7b, 0xc4, 0x9d, 0x2b, 0xf3, 0x9a, 0xd0, 0x57, 0x46, 0xad, 0x11, 0xf5, 0xac, 0xe2, 0x2f, - 0xfd, 0x56, 0x0c, 0xe6, 0x1a, 0x8f, 0xd7, 0x8a, 0x87, 0xb0, 0xc2, 0xf2, 0x22, 0xac, 0x4e, 0x30, - 0xe4, 0x1c, 0x7e, 0x0e, 0x39, 0xe2, 0x8f, 0xd7, 0x86, 0xe2, 0x2f, 0x12, 0xae, 0x83, 0x08, 0xa4, - 0x28, 0x8f, 0xd9, 0x3e, 0xef, 0xc0, 0xb2, 0x8a, 0xdb, 0x9a, 0xfa, 0x7d, 0xcd, 0xb3, 0xc4, 0xa5, - 0x1f, 0xb3, 0x75, 0xfe, 0x54, 0x80, 0x9c, 0x84, 0x2d, 0x83, 0x24, 0x08, 0x68, 0x13, 0xf2, 0x78, - 0xd4, 0xc6, 0x86, 0xed, 0xe4, 0x54, 0x93, 0x73, 0x53, 0xc6, 0xdd, 0x70, 0x38, 0x09, 0xd2, 0x72, - 0xc5, 0xd0, 0x0d, 0x0e, 0xaa, 0xa3, 0xf1, 0x31, 0x17, 0xf7, 0xa3, 0xea, 0x57, 0x1c, 0x54, 0x9d, - 0x8c, 0x04, 0x56, 0x4c, 0x2a, 0x04, 0xab, 0x6f, 0x70, 0x58, 0x9d, 0x9a, 0xf1, 0xb1, 0x00, 0xae, - 0xae, 0x07, 0x70, 0x75, 0x7a, 0xc6, 0x34, 0x23, 0x80, 0xf5, 0x2b, 0x0e, 0xb0, 0xce, 0xcc, 0x18, - 0x71, 0x08, 0x59, 0xdf, 0x0e, 0x22, 0xeb, 0x6c, 0x84, 0xdb, 0x71, 0xa4, 0xa7, 0x42, 0xeb, 0x37, - 0x7d, 0xd0, 0x3a, 0x17, 0x89, 0x69, 0x99, 0xa2, 0x09, 0xd8, 0xfa, 0xed, 0x00, 0xb6, 0xce, 0xcf, - 0xb0, 0xc3, 0x14, 0x70, 0xbd, 0xe5, 0x07, 0xd7, 0x10, 0x89, 0xd1, 0xf9, 0xba, 0x47, 0xa1, 0xeb, - 0xd7, 0x5c, 0x74, 0x5d, 0x88, 0x2c, 0x13, 0xf0, 0xb9, 0x84, 0xe1, 0xf5, 0xfe, 0x18, 0xbc, 0x66, - 0x70, 0xf8, 0xd9, 0x48, 0x15, 0x33, 0xf0, 0xf5, 0xfe, 0x18, 0xbe, 0x2e, 0xcd, 0x50, 0x38, 0x03, - 0x60, 0xbf, 0x3f, 0x19, 0x60, 0x47, 0x43, 0x60, 0x3e, 0xcc, 0xf9, 0x10, 0xb6, 0x1c, 0x81, 0xb0, - 0x2b, 0x91, 0x68, 0x90, 0xa9, 0x9f, 0x1b, 0x62, 0x1f, 0x4d, 0x80, 0xd8, 0x0c, 0x0c, 0x5f, 0x89, - 0x54, 0x3e, 0x07, 0xc6, 0x3e, 0x9a, 0x80, 0xb1, 0x97, 0x66, 0xaa, 0x9d, 0x09, 0xb2, 0xb7, 0x83, - 0x20, 0x1b, 0xcd, 0x38, 0x63, 0x91, 0x28, 0xfb, 0x38, 0x0a, 0x65, 0x33, 0x24, 0xfc, 0x62, 0xa4, - 0xc6, 0x05, 0x60, 0xf6, 0xfe, 0x18, 0xcc, 0x5e, 0x99, 0xb1, 0xd3, 0xe6, 0xc5, 0xd9, 0xcf, 0x93, - 0x54, 0x2f, 0xe4, 0xaa, 0x49, 0xb6, 0x88, 0x4d, 0x53, 0x37, 0x39, 0x62, 0x66, 0x1d, 0xf1, 0x0a, - 0xc1, 0x5d, 0x9e, 0x5b, 0x9e, 0x82, 0xc9, 0x69, 0x56, 0xee, 0x73, 0xc5, 0xe2, 0x6f, 0xe3, 0x9e, - 0x2c, 0x85, 0x2b, 0x7e, 0xcc, 0x96, 0xe7, 0x98, 0xcd, 0x87, 0xd4, 0x13, 0x41, 0xa4, 0xbe, 0x06, - 0x05, 0x92, 0x6d, 0x87, 0x40, 0xb8, 0x62, 0xb8, 0x20, 0xfc, 0x2a, 0x2c, 0xd1, 0xf0, 0xc9, 0xf0, - 0x3c, 0x4f, 0xb1, 0x53, 0x34, 0x0d, 0xaa, 0x90, 0x1f, 0x98, 0x15, 0x58, 0xae, 0xfd, 0x12, 0x2c, - 0xfb, 0x78, 0xdd, 0x2c, 0x9e, 0x21, 0x52, 0xc1, 0xe5, 0xde, 0xe0, 0xe9, 0xfc, 0x1f, 0xe2, 0x9e, - 0x85, 0x3c, 0xf4, 0x3e, 0x09, 0x68, 0xc7, 0x1f, 0x11, 0xd0, 0x4e, 0x7c, 0x6f, 0xa0, 0xed, 0x47, - 0x25, 0xc9, 0x20, 0x2a, 0xf9, 0x47, 0xdc, 0x5b, 0x13, 0x17, 0x36, 0xb7, 0x75, 0x15, 0x73, 0x9c, - 0x40, 0xdb, 0x24, 0x41, 0xe9, 0xe9, 0x1d, 0x8e, 0x06, 0x48, 0x93, 0x70, 0xb9, 0xb1, 0x33, 0xcf, - 0x43, 0xa3, 0x0b, 0x31, 0xd2, 0xd4, 0xc2, 0x1c, 0x62, 0x08, 0x90, 0x7c, 0x80, 0x59, 0xa4, 0x2b, - 0x4a, 0xa4, 0x49, 0xf8, 0xe8, 0x26, 0xa3, 0xf1, 0xab, 0x28, 0xb1, 0x0e, 0xba, 0x05, 0x79, 0x5a, - 0xfc, 0x97, 0x75, 0xc3, 0xe2, 0x01, 0x29, 0x90, 0xe8, 0xb0, 0x1a, 0xff, 0xfa, 0x01, 0xe1, 0xd9, - 0x37, 0x2c, 0x29, 0x67, 0xf0, 0x96, 0x0f, 0x3d, 0xe5, 0x03, 0x00, 0xfe, 0x02, 0xe4, 0xc9, 0xe8, - 0x2d, 0x43, 0x69, 0x63, 0x1a, 0x59, 0xf2, 0x92, 0x47, 0x10, 0xef, 0x03, 0x1a, 0x8f, 0x93, 0xa8, - 0x09, 0x19, 0x7c, 0x8a, 0x07, 0x36, 0x59, 0xb6, 0x64, 0x18, 0x85, 0xf0, 0xbc, 0x08, 0x0f, 0xec, - 0xcd, 0x2a, 0x31, 0xf2, 0xdf, 0xbf, 0x5e, 0x13, 0x18, 0xf7, 0x8b, 0x7a, 0x5f, 0xb3, 0x71, 0xdf, - 0xb0, 0xcf, 0x24, 0x2e, 0x2f, 0xfe, 0x25, 0x41, 0xe0, 0x6a, 0x20, 0x7e, 0x4e, 0xb4, 0xad, 0xb3, - 0xe5, 0x13, 0xbe, 0x32, 0xc5, 0x7c, 0xf6, 0xbe, 0x08, 0xd0, 0x51, 0x2c, 0xf9, 0x63, 0x65, 0x60, - 0x63, 0x95, 0x1b, 0x3d, 0xdf, 0x51, 0xac, 0x77, 0x29, 0x81, 0xac, 0x3a, 0xf9, 0x79, 0x68, 0x61, - 0x95, 0xa7, 0xfe, 0xd9, 0x8e, 0x62, 0x1d, 0x59, 0x58, 0xf5, 0xcd, 0x32, 0xfb, 0x70, 0xb3, 0x0c, - 0xda, 0x38, 0x17, 0xb2, 0xb1, 0x0f, 0x48, 0xe6, 0xfd, 0x40, 0x12, 0xd5, 0x20, 0x67, 0x98, 0x9a, - 0x6e, 0x6a, 0xf6, 0x19, 0x5d, 0x98, 0xa4, 0xe4, 0xf6, 0xd1, 0x65, 0x28, 0xf5, 0x71, 0xdf, 0xd0, - 0xf5, 0x9e, 0xcc, 0x9c, 0x4d, 0x81, 0x8a, 0x16, 0x39, 0xb1, 0x41, 0x7d, 0xce, 0xa7, 0x09, 0xef, - 0xf4, 0x79, 0x05, 0x83, 0x47, 0x6b, 0xde, 0xd5, 0x09, 0xe6, 0xf5, 0x51, 0xc8, 0x24, 0x42, 0xf6, - 0x75, 0xfb, 0x3f, 0x94, 0x81, 0xc5, 0x9f, 0xd0, 0x12, 0x62, 0x30, 0x37, 0x42, 0x87, 0xb0, 0xe4, - 0x1e, 0x7e, 0x79, 0x48, 0x9d, 0x82, 0xb3, 0x9d, 0xe7, 0xf5, 0x1e, 0xc2, 0x69, 0x90, 0x6c, 0xa1, - 0xf7, 0xe0, 0xc9, 0x90, 0x67, 0x73, 0x55, 0x27, 0xe6, 0x75, 0x70, 0x4f, 0x04, 0x1d, 0x9c, 0xa3, - 0xda, 0x33, 0x56, 0xf2, 0x21, 0xcf, 0xdc, 0x0e, 0x94, 0x83, 0x69, 0xde, 0xc4, 0xe5, 0xbf, 0x0c, - 0x25, 0x13, 0xdb, 0x8a, 0x36, 0x90, 0x03, 0x75, 0xbf, 0x22, 0x23, 0xf2, 0x6a, 0xe2, 0x01, 0x3c, - 0x31, 0x31, 0xdd, 0x43, 0xaf, 0x42, 0xde, 0xcb, 0x14, 0xe3, 0x11, 0xe0, 0xc9, 0x2d, 0x0d, 0x79, - 0xbc, 0xe2, 0xef, 0xe2, 0x9e, 0xca, 0x60, 0xb1, 0xa9, 0x01, 0x19, 0x13, 0x5b, 0xc3, 0x1e, 0x2b, - 0xff, 0x94, 0xaf, 0xbf, 0x34, 0x5f, 0xa2, 0x48, 0xa8, 0xc3, 0x9e, 0x2d, 0x71, 0x61, 0xf1, 0x3e, - 0x64, 0x18, 0x05, 0x15, 0x20, 0x7b, 0xb4, 0x77, 0x67, 0x6f, 0xff, 0xdd, 0x3d, 0x21, 0x86, 0x00, - 0x32, 0x1b, 0xf5, 0x7a, 0xe3, 0xa0, 0x25, 0xc4, 0x51, 0x1e, 0xd2, 0x1b, 0x9b, 0xfb, 0x52, 0x4b, - 0x48, 0x10, 0xb2, 0xd4, 0xb8, 0xdd, 0xa8, 0xb7, 0x84, 0x24, 0x5a, 0x82, 0x12, 0x6b, 0xcb, 0xdb, - 0xfb, 0xd2, 0xdd, 0x8d, 0x96, 0x90, 0xf2, 0x91, 0x0e, 0x1b, 0x7b, 0x5b, 0x0d, 0x49, 0x48, 0x8b, - 0x2f, 0xc3, 0xf9, 0xc8, 0xd4, 0xd2, 0xab, 0x24, 0xc5, 0x7d, 0x95, 0x24, 0xf1, 0xe7, 0x09, 0xa8, - 0x45, 0xe7, 0x8b, 0xe8, 0x76, 0x68, 0xe2, 0xd7, 0x17, 0x48, 0x36, 0x43, 0xb3, 0x47, 0xcf, 0x40, - 0xd9, 0xc4, 0x27, 0xd8, 0x6e, 0x77, 0x59, 0xfe, 0xca, 0x02, 0x66, 0x49, 0x2a, 0x71, 0x2a, 0x15, - 0xb2, 0x18, 0xdb, 0x87, 0xb8, 0x6d, 0xcb, 0xcc, 0x17, 0xb1, 0x4d, 0x97, 0x27, 0x6c, 0x84, 0x7a, - 0xc8, 0x88, 0xe2, 0x07, 0x0b, 0xd9, 0x32, 0x0f, 0x69, 0xa9, 0xd1, 0x92, 0xde, 0x13, 0x92, 0x08, - 0x41, 0x99, 0x36, 0xe5, 0xc3, 0xbd, 0x8d, 0x83, 0xc3, 0xe6, 0x3e, 0xb1, 0xe5, 0x32, 0x54, 0x1c, - 0x5b, 0x3a, 0xc4, 0xb4, 0xf8, 0xbe, 0x17, 0x7f, 0x7c, 0xd5, 0xb4, 0x6d, 0x28, 0x87, 0xd2, 0xc5, - 0xf8, 0x38, 0x9e, 0xf1, 0xaa, 0x61, 0x6e, 0x2a, 0x28, 0x95, 0x4e, 0xfd, 0x5d, 0xf1, 0xd7, 0x71, - 0x78, 0x6a, 0x4a, 0x42, 0x89, 0xde, 0x81, 0x8c, 0x65, 0x2b, 0xf6, 0xd0, 0xe2, 0x96, 0x7f, 0x6d, - 0x91, 0x74, 0x74, 0x9d, 0xd1, 0x0e, 0xa9, 0x02, 0x89, 0x2b, 0x12, 0x6f, 0x40, 0xd1, 0x4f, 0x8f, - 0x36, 0x9c, 0xb7, 0xf3, 0x12, 0xe2, 0x77, 0x49, 0x78, 0x32, 0x22, 0xe7, 0x47, 0x1d, 0x40, 0x7d, - 0x5d, 0xd5, 0x4e, 0x34, 0xac, 0xca, 0xf6, 0x48, 0x9e, 0x73, 0xbc, 0x21, 0x2d, 0xeb, 0x77, 0xb9, - 0x8a, 0xd6, 0x88, 0x8f, 0x57, 0xe8, 0x87, 0x28, 0xe8, 0x16, 0x80, 0x3d, 0x92, 0x4d, 0xdc, 0xd6, - 0x4d, 0xd5, 0xc9, 0xb3, 0xc6, 0xcf, 0x74, 0x6b, 0x24, 0x51, 0x0e, 0x29, 0x6f, 0xf3, 0xd6, 0xb4, - 0xcc, 0x0a, 0xbd, 0xc1, 0x95, 0x92, 0x4d, 0xe4, 0xd4, 0xdb, 0x2f, 0x4e, 0xa8, 0x10, 0xe2, 0x36, - 0x51, 0x4c, 0xb7, 0x32, 0x55, 0x4c, 0xf9, 0xd1, 0xdd, 0x49, 0x3e, 0x3c, 0x3d, 0x9f, 0x0f, 0x5f, - 0xcc, 0x7b, 0x67, 0x1e, 0xce, 0x7b, 0x8b, 0x6f, 0x82, 0x10, 0x36, 0x71, 0x70, 0xe9, 0xcb, 0x00, - 0x47, 0x7b, 0x77, 0xf7, 0xb7, 0x76, 0xb6, 0x77, 0x1a, 0x5b, 0x42, 0x1c, 0x15, 0x21, 0xe7, 0xf6, - 0x12, 0xe2, 0xaf, 0x02, 0x1b, 0x20, 0x08, 0xc5, 0xf6, 0x43, 0x9b, 0xf4, 0xd5, 0x79, 0x71, 0xdd, - 0xba, 0xd3, 0x08, 0x6e, 0xd1, 0x29, 0xe5, 0xf9, 0xd0, 0x72, 0x25, 0x1f, 0xc5, 0x72, 0xa5, 0x1e, - 0xc7, 0x72, 0xa5, 0x1f, 0x72, 0xb9, 0x6e, 0x42, 0x39, 0x68, 0x9c, 0xf9, 0xce, 0xe9, 0x4f, 0x93, - 0x5e, 0xf0, 0x0a, 0x16, 0x42, 0x1f, 0x59, 0xc6, 0x1c, 0x5a, 0x82, 0xc4, 0x82, 0x4b, 0x30, 0x31, - 0xeb, 0x49, 0x3e, 0xbe, 0xac, 0x27, 0xf5, 0x90, 0x59, 0x8f, 0x7f, 0x2f, 0xa6, 0x83, 0x7b, 0x71, - 0x2c, 0x41, 0xc9, 0x4c, 0x48, 0x50, 0xde, 0x03, 0xf0, 0xdd, 0xf3, 0xad, 0x40, 0xda, 0xd4, 0x87, - 0x03, 0x95, 0x9e, 0x94, 0xb4, 0xc4, 0x3a, 0xe8, 0x26, 0xa4, 0x49, 0x58, 0x88, 0xf6, 0x69, 0xc4, - 0xad, 0xfb, 0xca, 0xc6, 0x8c, 0x5b, 0xd4, 0x00, 0x8d, 0xdf, 0x5c, 0x44, 0x7c, 0xe2, 0xcd, 0xe0, - 0x27, 0x9e, 0x8e, 0xbc, 0x03, 0x99, 0xfc, 0xa9, 0x4f, 0x20, 0x4d, 0xb7, 0x07, 0x49, 0xd4, 0xe8, - 0x95, 0x21, 0x47, 0xfe, 0xa4, 0x8d, 0xfe, 0x1f, 0x40, 0xb1, 0x6d, 0x53, 0x3b, 0x1e, 0x7a, 0x1f, - 0x58, 0x9b, 0xbc, 0xbd, 0x36, 0x1c, 0xbe, 0xcd, 0x0b, 0x7c, 0x9f, 0xad, 0x78, 0xa2, 0xbe, 0xbd, - 0xe6, 0x53, 0x28, 0xee, 0x41, 0x39, 0x28, 0xeb, 0x60, 0x55, 0x36, 0x86, 0x20, 0x56, 0x65, 0xa5, - 0x07, 0x8e, 0x55, 0x5d, 0xa4, 0x9b, 0x64, 0x57, 0xc3, 0xb4, 0x23, 0x7e, 0x17, 0x87, 0xa2, 0x7f, - 0x77, 0xfe, 0xa7, 0xc1, 0x3d, 0xf1, 0xd3, 0x38, 0xe4, 0xdc, 0xc9, 0x47, 0x5c, 0xcd, 0x7a, 0xb6, - 0x4b, 0xf8, 0x2f, 0x22, 0xd9, 0x5d, 0x6f, 0xd2, 0xbd, 0x41, 0x7e, 0xdd, 0xcd, 0x0c, 0xa3, 0xaa, - 0xf3, 0x7e, 0x4b, 0x3b, 0xf7, 0x29, 0x3c, 0x11, 0xfe, 0x19, 0x1f, 0x07, 0x89, 0xd1, 0xe8, 0xbf, - 0x21, 0xa3, 0xb4, 0xdd, 0x3b, 0x89, 0xf2, 0x84, 0x22, 0xb5, 0xc3, 0xba, 0xde, 0x1a, 0x6d, 0x50, - 0x4e, 0x89, 0x4b, 0xf0, 0x51, 0x25, 0xdc, 0x1b, 0xe8, 0xb7, 0x88, 0x5e, 0xc6, 0x33, 0x3d, 0xc6, - 0x91, 0xdc, 0x70, 0x6b, 0x8b, 0x04, 0x38, 0xc2, 0x27, 0x35, 0xee, 0xee, 0xdf, 0x6b, 0x6c, 0x09, - 0x49, 0xf1, 0x75, 0xc8, 0xbb, 0xae, 0x07, 0x55, 0x21, 0xab, 0xa8, 0xaa, 0x89, 0x2d, 0x8b, 0x27, - 0xcd, 0x4e, 0x97, 0x3e, 0x3d, 0xd0, 0x3f, 0xe6, 0xf7, 0xaf, 0x49, 0x89, 0x75, 0x44, 0x15, 0x2a, - 0x21, 0xbf, 0x85, 0x5e, 0x87, 0xac, 0x31, 0x3c, 0x96, 0x9d, 0x4d, 0x1b, 0x7a, 0x1c, 0xe8, 0x94, - 0x4c, 0x86, 0xc7, 0x3d, 0xad, 0x7d, 0x07, 0x9f, 0x39, 0x66, 0x32, 0x86, 0xc7, 0x77, 0xd8, 0xde, - 0x66, 0x5f, 0x49, 0xf8, 0xbf, 0xf2, 0xe3, 0x38, 0xe4, 0x9c, 0xb3, 0x8a, 0xfe, 0x07, 0xf2, 0xae, - 0x4f, 0x74, 0x9f, 0xa4, 0x44, 0x3a, 0x53, 0xae, 0xdf, 0x13, 0x41, 0x57, 0x61, 0xc9, 0xd2, 0x3a, - 0x03, 0xe7, 0x1a, 0x8b, 0xd5, 0x28, 0x13, 0xf4, 0xd0, 0x54, 0xd8, 0x0f, 0xbb, 0x4e, 0x61, 0xed, - 0x76, 0x2a, 0x97, 0x14, 0x52, 0xb7, 0x53, 0xb9, 0x94, 0x90, 0x26, 0xe9, 0xab, 0x10, 0x76, 0x1c, - 0x3f, 0xe4, 0x60, 0x08, 0x4c, 0x08, 0xe5, 0xe1, 0x6c, 0x6f, 0x86, 0xd2, 0xec, 0x7f, 0xc6, 0x21, - 0xe7, 0x5c, 0x94, 0xa1, 0x97, 0x7d, 0x2e, 0xac, 0x3c, 0x69, 0xc7, 0x72, 0x46, 0xef, 0xd9, 0x43, - 0x70, 0x4a, 0x89, 0xc5, 0xa7, 0x14, 0xf5, 0x76, 0xc5, 0x79, 0x45, 0x94, 0x5a, 0xf8, 0x15, 0xd1, - 0x8b, 0x80, 0x6c, 0xdd, 0x56, 0x7a, 0xf2, 0xa9, 0x6e, 0x6b, 0x83, 0x8e, 0xcc, 0x76, 0x08, 0xf3, - 0x36, 0x02, 0xfd, 0xe5, 0x1e, 0xfd, 0xe1, 0xc0, 0xdd, 0x2c, 0x2e, 0x8c, 0x5d, 0xf4, 0x15, 0xc3, - 0x39, 0xc8, 0x70, 0xa4, 0xc6, 0x9e, 0x31, 0xf0, 0x9e, 0x7b, 0xb5, 0x9a, 0xf2, 0x5d, 0xad, 0xd6, - 0x20, 0xd7, 0xc7, 0xb6, 0x42, 0x5d, 0x27, 0x8b, 0x96, 0x6e, 0xff, 0xea, 0x6b, 0x50, 0xf0, 0x3d, - 0x28, 0x21, 0xde, 0x74, 0xaf, 0xf1, 0xae, 0x10, 0xab, 0x65, 0x3f, 0xfb, 0xe2, 0x52, 0x72, 0x0f, - 0x7f, 0x4c, 0x0e, 0x9a, 0xd4, 0xa8, 0x37, 0x1b, 0xf5, 0x3b, 0x42, 0xbc, 0x56, 0xf8, 0xec, 0x8b, - 0x4b, 0x59, 0x09, 0xd3, 0x7b, 0xac, 0xab, 0x4d, 0x28, 0xfa, 0x57, 0x25, 0x78, 0xa8, 0x11, 0x94, - 0xb7, 0x8e, 0x0e, 0x76, 0x77, 0xea, 0x1b, 0xad, 0x86, 0x7c, 0x6f, 0xbf, 0xd5, 0x10, 0xe2, 0xe8, - 0x49, 0x58, 0xde, 0xdd, 0x79, 0xbb, 0xd9, 0x92, 0xeb, 0xbb, 0x3b, 0x8d, 0xbd, 0x96, 0xbc, 0xd1, - 0x6a, 0x6d, 0xd4, 0xef, 0x08, 0x89, 0xeb, 0xbf, 0x29, 0x40, 0x65, 0x63, 0xb3, 0xbe, 0x43, 0x80, - 0xaa, 0xd6, 0x56, 0xa8, 0x8b, 0xa8, 0x43, 0x8a, 0x56, 0xc4, 0xa7, 0x3e, 0x0e, 0xae, 0x4d, 0xbf, - 0xe5, 0x44, 0xdb, 0x90, 0xa6, 0xc5, 0x72, 0x34, 0xfd, 0xb5, 0x70, 0x6d, 0xc6, 0xb5, 0x27, 0x19, - 0x0c, 0x3d, 0x45, 0x53, 0x9f, 0x0f, 0xd7, 0xa6, 0xdf, 0x82, 0xa2, 0x5d, 0xc8, 0x3a, 0xb5, 0xcc, - 0x59, 0x0f, 0x71, 0x6b, 0x33, 0xaf, 0x13, 0xc9, 0xd4, 0x58, 0xcd, 0x79, 0xfa, 0xcb, 0xe2, 0xda, - 0x8c, 0xfb, 0x51, 0xb4, 0x03, 0x19, 0x5e, 0xee, 0x99, 0xf1, 0xa8, 0xb6, 0x36, 0xeb, 0x5a, 0x10, - 0x49, 0x90, 0xf7, 0xaa, 0xf9, 0xb3, 0xdf, 0x4b, 0xd7, 0xe6, 0xb8, 0xfa, 0x45, 0xf7, 0xa1, 0x14, - 0x2c, 0x21, 0xcd, 0xf7, 0x70, 0xb7, 0x36, 0xe7, 0x05, 0x24, 0xd1, 0x1f, 0xac, 0x27, 0xcd, 0xf7, - 0x90, 0xb7, 0x36, 0xe7, 0x7d, 0x24, 0xfa, 0x10, 0x96, 0xc6, 0xeb, 0x3d, 0xf3, 0xbf, 0xeb, 0xad, - 0x2d, 0x70, 0x43, 0x89, 0xfa, 0x80, 0x26, 0xd4, 0x89, 0x16, 0x78, 0xe6, 0x5b, 0x5b, 0xe4, 0xc2, - 0x12, 0xa9, 0x50, 0x09, 0x57, 0x1d, 0xe6, 0x7d, 0xf6, 0x5b, 0x9b, 0xfb, 0xf2, 0x92, 0x7d, 0x25, - 0x08, 0x6d, 0xe7, 0x7d, 0x06, 0x5c, 0x9b, 0xfb, 0x2e, 0x13, 0x1d, 0x01, 0xf8, 0x0a, 0x49, 0x73, - 0x3c, 0x0b, 0xae, 0xcd, 0x73, 0xab, 0x89, 0x0c, 0x58, 0x9e, 0x54, 0x40, 0x5a, 0xe4, 0x95, 0x70, - 0x6d, 0xa1, 0xcb, 0x4e, 0xb2, 0x9f, 0x83, 0x10, 0x73, 0xbe, 0x57, 0xc3, 0xb5, 0x39, 0x6f, 0x3d, - 0x37, 0x1b, 0x5f, 0x7e, 0xb3, 0x1a, 0xff, 0xea, 0x9b, 0xd5, 0xf8, 0xdf, 0xbe, 0x59, 0x8d, 0x7f, - 0xfe, 0xed, 0x6a, 0xec, 0xab, 0x6f, 0x57, 0x63, 0x7f, 0xfe, 0x76, 0x35, 0xf6, 0xbf, 0x2f, 0x74, - 0x34, 0xbb, 0x3b, 0x3c, 0x5e, 0x6f, 0xeb, 0xfd, 0x6b, 0xfe, 0x3f, 0x90, 0x4c, 0xfa, 0x53, 0xcb, - 0x71, 0x86, 0x46, 0xd3, 0x1b, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xb5, 0xc1, 0x14, 0x70, 0xf4, - 0x32, 0x00, 0x00, + // 3386 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0xcd, 0x73, 0x1c, 0xd5, + 0x11, 0xdf, 0xef, 0x8f, 0xde, 0x4f, 0x3d, 0x09, 0xb3, 0x5e, 0x6c, 0xc9, 0x8c, 0x0b, 0x30, 0x06, + 0xe4, 0x60, 0x97, 0xc1, 0x04, 0x08, 0x25, 0xad, 0x56, 0xac, 0x6c, 0x59, 0x12, 0xa3, 0x95, 0x28, + 0x12, 0xe2, 0x61, 0xb4, 0xf3, 0xa4, 0x1d, 0xbc, 0x3b, 0x33, 0xcc, 0xcc, 0x8a, 0x15, 0xa7, 0x54, + 0xaa, 0xb8, 0x50, 0xa9, 0x0a, 0xb7, 0xa4, 0x2a, 0x45, 0xe5, 0x92, 0x54, 0xe5, 0x4f, 0xc8, 0x29, + 0x97, 0xe4, 0xc0, 0x21, 0x07, 0x4e, 0x49, 0x2a, 0x07, 0x92, 0x82, 0x5b, 0xfe, 0x81, 0x9c, 0xf2, + 0x51, 0xef, 0x63, 0x3e, 0x77, 0x67, 0x3f, 0xb0, 0xcd, 0x25, 0xb9, 0xcd, 0xeb, 0xed, 0xee, 0x99, + 0xd7, 0xaf, 0x5f, 0x77, 0xff, 0xfa, 0xbd, 0x85, 0x27, 0x6c, 0xac, 0x29, 0xd8, 0xec, 0xab, 0x9a, + 0x7d, 0x4d, 0x3e, 0xea, 0xa8, 0xd7, 0xec, 0x33, 0x03, 0x5b, 0xab, 0x86, 0xa9, 0xdb, 0x3a, 0xaa, + 0x78, 0x3f, 0xae, 0x92, 0x1f, 0xeb, 0x17, 0x7d, 0xdc, 0x1d, 0xf3, 0xcc, 0xb0, 0xf5, 0x6b, 0x86, + 0xa9, 0xeb, 0xc7, 0x8c, 0xbf, 0x7e, 0xc1, 0xf7, 0x33, 0xd5, 0xe3, 0xd7, 0x16, 0xf8, 0x95, 0x0b, + 0xdf, 0xc7, 0x67, 0xce, 0xaf, 0x17, 0x47, 0x64, 0x0d, 0xd9, 0x94, 0xfb, 0xce, 0xcf, 0x2b, 0x27, + 0xba, 0x7e, 0xd2, 0xc3, 0xd7, 0xe8, 0xe8, 0x68, 0x70, 0x7c, 0xcd, 0x56, 0xfb, 0xd8, 0xb2, 0xe5, + 0xbe, 0xc1, 0x19, 0x96, 0x4e, 0xf4, 0x13, 0x9d, 0x3e, 0x5e, 0x23, 0x4f, 0x8c, 0x2a, 0xfc, 0x07, + 0x20, 0x2b, 0xe2, 0x0f, 0x06, 0xd8, 0xb2, 0xd1, 0x75, 0x48, 0xe1, 0x4e, 0x57, 0xaf, 0xc5, 0x2f, + 0xc5, 0xaf, 0x14, 0xae, 0x5f, 0x58, 0x0d, 0x4d, 0x6e, 0x95, 0xf3, 0x35, 0x3b, 0x5d, 0xbd, 0x15, + 0x13, 0x29, 0x2f, 0xba, 0x09, 0xe9, 0xe3, 0xde, 0xc0, 0xea, 0xd6, 0x12, 0x54, 0xe8, 0x62, 0x94, + 0xd0, 0x26, 0x61, 0x6a, 0xc5, 0x44, 0xc6, 0x4d, 0x5e, 0xa5, 0x6a, 0xc7, 0x7a, 0x2d, 0x39, 0xf9, + 0x55, 0x5b, 0xda, 0x31, 0x7d, 0x15, 0xe1, 0x45, 0xeb, 0x00, 0xaa, 0xa6, 0xda, 0x52, 0xa7, 0x2b, + 0xab, 0x5a, 0x2d, 0x45, 0x25, 0x9f, 0x8c, 0x96, 0x54, 0xed, 0x06, 0x61, 0x6c, 0xc5, 0xc4, 0xbc, + 0xea, 0x0c, 0xc8, 0xe7, 0x7e, 0x30, 0xc0, 0xe6, 0x59, 0x2d, 0x3d, 0xf9, 0x73, 0xdf, 0x22, 0x4c, + 0xe4, 0x73, 0x29, 0x37, 0xda, 0x82, 0xc2, 0x11, 0x3e, 0x51, 0x35, 0xe9, 0xa8, 0xa7, 0x77, 0xee, + 0xd7, 0x32, 0x54, 0x58, 0x88, 0x12, 0x5e, 0x27, 0xac, 0xeb, 0x84, 0x73, 0x3d, 0x51, 0x8b, 0xb7, + 0x62, 0x22, 0x1c, 0xb9, 0x14, 0xf4, 0x1a, 0xe4, 0x3a, 0x5d, 0xdc, 0xb9, 0x2f, 0xd9, 0xc3, 0x5a, + 0x96, 0xea, 0x59, 0x89, 0xd2, 0xd3, 0x20, 0x7c, 0xed, 0x61, 0x2b, 0x26, 0x66, 0x3b, 0xec, 0x11, + 0x6d, 0x02, 0x28, 0xb8, 0xa7, 0x9e, 0x62, 0x93, 0xc8, 0xe7, 0x26, 0xdb, 0x60, 0x83, 0x71, 0xb6, + 0x87, 0xfc, 0x33, 0xf2, 0x8a, 0x43, 0x40, 0x0d, 0xc8, 0x63, 0x4d, 0xe1, 0xd3, 0xc9, 0x53, 0x35, + 0x97, 0x22, 0xd7, 0x5b, 0x53, 0xfc, 0x93, 0xc9, 0x61, 0x3e, 0x46, 0xb7, 0x20, 0xd3, 0xd1, 0xfb, + 0x7d, 0xd5, 0xae, 0x01, 0xd5, 0xb0, 0x1c, 0x39, 0x11, 0xca, 0xd5, 0x8a, 0x89, 0x9c, 0x1f, 0xed, + 0x40, 0xb9, 0xa7, 0x5a, 0xb6, 0x64, 0x69, 0xb2, 0x61, 0x75, 0x75, 0xdb, 0xaa, 0x15, 0xa8, 0x86, + 0xa7, 0xa2, 0x34, 0x6c, 0xab, 0x96, 0xbd, 0xef, 0x30, 0xb7, 0x62, 0x62, 0xa9, 0xe7, 0x27, 0x10, + 0x7d, 0xfa, 0xf1, 0x31, 0x36, 0x5d, 0x85, 0xb5, 0xe2, 0x64, 0x7d, 0xbb, 0x84, 0xdb, 0x91, 0x27, + 0xfa, 0x74, 0x3f, 0x01, 0xfd, 0x00, 0x16, 0x7b, 0xba, 0xac, 0xb8, 0xea, 0xa4, 0x4e, 0x77, 0xa0, + 0xdd, 0xaf, 0x95, 0xa8, 0xd2, 0x67, 0x23, 0x3f, 0x52, 0x97, 0x15, 0x47, 0x45, 0x83, 0x08, 0xb4, + 0x62, 0xe2, 0x42, 0x2f, 0x4c, 0x44, 0xf7, 0x60, 0x49, 0x36, 0x8c, 0xde, 0x59, 0x58, 0x7b, 0x99, + 0x6a, 0xbf, 0x1a, 0xa5, 0x7d, 0x8d, 0xc8, 0x84, 0xd5, 0x23, 0x79, 0x84, 0x8a, 0xda, 0x50, 0x35, + 0x4c, 0x6c, 0xc8, 0x26, 0x96, 0x0c, 0x53, 0x37, 0x74, 0x4b, 0xee, 0xd5, 0x2a, 0x54, 0xf7, 0x33, + 0x51, 0xba, 0xf7, 0x18, 0xff, 0x1e, 0x67, 0x6f, 0xc5, 0xc4, 0x8a, 0x11, 0x24, 0x31, 0xad, 0x7a, + 0x07, 0x5b, 0x96, 0xa7, 0xb5, 0x3a, 0x4d, 0x2b, 0xe5, 0x0f, 0x6a, 0x0d, 0x90, 0x50, 0x13, 0x0a, + 0x78, 0x48, 0xc4, 0xa5, 0x53, 0xdd, 0xc6, 0xb5, 0x85, 0xc9, 0x1b, 0xab, 0x49, 0x59, 0x0f, 0x75, + 0x1b, 0x93, 0x4d, 0x85, 0xdd, 0x11, 0x92, 0xe1, 0xb1, 0x53, 0x6c, 0xaa, 0xc7, 0x67, 0x54, 0x8d, + 0x44, 0x7f, 0xb1, 0x54, 0x5d, 0xab, 0x21, 0xaa, 0xf0, 0xb9, 0x28, 0x85, 0x87, 0x54, 0x88, 0xa8, + 0x68, 0x3a, 0x22, 0xad, 0x98, 0xb8, 0x78, 0x3a, 0x4a, 0x26, 0x2e, 0x76, 0xac, 0x6a, 0x72, 0x4f, + 0xfd, 0x08, 0xf3, 0x6d, 0xb3, 0x38, 0xd9, 0xc5, 0x36, 0x39, 0x37, 0xdd, 0x2b, 0xc4, 0xc5, 0x8e, + 0xfd, 0x84, 0xf5, 0x2c, 0xa4, 0x4f, 0xe5, 0xde, 0x00, 0x0b, 0xcf, 0x40, 0xc1, 0x17, 0x58, 0x51, + 0x0d, 0xb2, 0x7d, 0x6c, 0x59, 0xf2, 0x09, 0xa6, 0x71, 0x38, 0x2f, 0x3a, 0x43, 0xa1, 0x0c, 0x45, + 0x7f, 0x30, 0x15, 0x3e, 0x8d, 0xbb, 0x92, 0x24, 0x4e, 0x12, 0xc9, 0x53, 0x6c, 0xd2, 0x69, 0x73, + 0x49, 0x3e, 0x44, 0x97, 0xa1, 0x44, 0x3f, 0x59, 0x72, 0x7e, 0x27, 0xc1, 0x3a, 0x25, 0x16, 0x29, + 0xf1, 0x90, 0x33, 0xad, 0x40, 0xc1, 0xb8, 0x6e, 0xb8, 0x2c, 0x49, 0xca, 0x02, 0xc6, 0x75, 0xc3, + 0x61, 0x78, 0x12, 0x8a, 0x64, 0x7e, 0x2e, 0x47, 0x8a, 0xbe, 0xa4, 0x40, 0x68, 0x9c, 0x45, 0xf8, + 0x63, 0x02, 0xaa, 0xe1, 0x00, 0x8c, 0x6e, 0x41, 0x8a, 0xe4, 0x22, 0x9e, 0x56, 0xea, 0xab, 0x2c, + 0x51, 0xad, 0x3a, 0x89, 0x6a, 0xb5, 0xed, 0x24, 0xaa, 0xf5, 0xdc, 0xe7, 0x5f, 0xae, 0xc4, 0x3e, + 0xfd, 0xdb, 0x4a, 0x5c, 0xa4, 0x12, 0xe8, 0x3c, 0x89, 0x95, 0xb2, 0xaa, 0x49, 0xaa, 0x42, 0x3f, + 0x39, 0x4f, 0x02, 0xa1, 0xac, 0x6a, 0x5b, 0x0a, 0xda, 0x86, 0x6a, 0x47, 0xd7, 0x2c, 0xac, 0x59, + 0x03, 0x4b, 0x62, 0x89, 0x90, 0x27, 0x93, 0x40, 0x38, 0x64, 0xe9, 0xb5, 0xe1, 0x70, 0xee, 0x51, + 0x46, 0xb1, 0xd2, 0x09, 0x12, 0x48, 0x58, 0x3d, 0x95, 0x7b, 0xaa, 0x22, 0xdb, 0xba, 0x69, 0xd5, + 0x52, 0x97, 0x92, 0x63, 0xe3, 0xe1, 0xa1, 0xc3, 0x72, 0x60, 0x28, 0xb2, 0x8d, 0xd7, 0x53, 0xe4, + 0x73, 0x45, 0x9f, 0x24, 0x7a, 0x1a, 0x2a, 0xb2, 0x61, 0x48, 0x96, 0x2d, 0xdb, 0x58, 0x3a, 0x3a, + 0xb3, 0xb1, 0x45, 0x13, 0x4d, 0x51, 0x2c, 0xc9, 0x86, 0xb1, 0x4f, 0xa8, 0xeb, 0x84, 0x88, 0x9e, + 0x82, 0x32, 0xc9, 0x49, 0xaa, 0xdc, 0x93, 0xba, 0x58, 0x3d, 0xe9, 0xda, 0x34, 0xa5, 0x24, 0xc5, + 0x12, 0xa7, 0xb6, 0x28, 0x51, 0x50, 0xdc, 0x15, 0xa7, 0xf9, 0x08, 0x21, 0x48, 0x29, 0xb2, 0x2d, + 0x53, 0x4b, 0x16, 0x45, 0xfa, 0x4c, 0x68, 0x86, 0x6c, 0x77, 0xb9, 0x7d, 0xe8, 0x33, 0x3a, 0x07, + 0x19, 0xae, 0x36, 0x49, 0xd5, 0xf2, 0x11, 0x5a, 0x82, 0xb4, 0x61, 0xea, 0xa7, 0x98, 0x2e, 0x5d, + 0x4e, 0x64, 0x03, 0xe1, 0x47, 0x09, 0x58, 0x18, 0xc9, 0x5c, 0x44, 0x6f, 0x57, 0xb6, 0xba, 0xce, + 0xbb, 0xc8, 0x33, 0x7a, 0x89, 0xe8, 0x95, 0x15, 0x6c, 0xf2, 0x6c, 0x5f, 0x1b, 0x35, 0x75, 0x8b, + 0xfe, 0xce, 0x4d, 0xc3, 0xb9, 0xd1, 0x1d, 0xa8, 0xf6, 0x64, 0xcb, 0x96, 0x58, 0xf4, 0x97, 0x7c, + 0x99, 0xff, 0x89, 0x11, 0x23, 0xb3, 0x5c, 0x41, 0x1c, 0x9a, 0x2b, 0x29, 0x13, 0x51, 0x8f, 0x8a, + 0x44, 0x58, 0x3a, 0x3a, 0xfb, 0x48, 0xd6, 0x6c, 0x55, 0xc3, 0xd2, 0xc8, 0xaa, 0x9d, 0x1f, 0x51, + 0xd8, 0x3c, 0x55, 0x15, 0xac, 0x75, 0x9c, 0xe5, 0x5a, 0x74, 0x85, 0xdd, 0xe5, 0xb4, 0x04, 0x11, + 0xca, 0xc1, 0x9c, 0x8b, 0xca, 0x90, 0xb0, 0x87, 0x7c, 0xf2, 0x09, 0x7b, 0x88, 0xbe, 0x03, 0x29, + 0x32, 0x41, 0x3a, 0xf1, 0xf2, 0x98, 0x82, 0x85, 0xcb, 0xb5, 0xcf, 0x0c, 0x2c, 0x52, 0x4e, 0x41, + 0x70, 0xb7, 0x82, 0x9b, 0x87, 0xc3, 0x5a, 0x85, 0x67, 0xa1, 0x12, 0x4a, 0xb2, 0xbe, 0xb5, 0x8b, + 0xfb, 0xd7, 0x4e, 0xa8, 0x40, 0x29, 0x90, 0x4d, 0x85, 0x73, 0xb0, 0x34, 0x2e, 0x39, 0x0a, 0x5d, + 0x97, 0x1e, 0x48, 0x72, 0xe8, 0x26, 0xe4, 0xdc, 0xec, 0xc8, 0xb6, 0xe2, 0xa8, 0xad, 0x1c, 0x66, + 0xd1, 0x65, 0x25, 0x7b, 0x90, 0xb8, 0x34, 0xf5, 0x85, 0x04, 0xfd, 0xf0, 0xac, 0x6c, 0x18, 0x2d, + 0xd9, 0xea, 0x0a, 0xef, 0x41, 0x2d, 0x2a, 0xf3, 0x85, 0xa6, 0x91, 0x72, 0x5d, 0xf0, 0x1c, 0x64, + 0x8e, 0x75, 0xb3, 0x2f, 0xdb, 0x54, 0x59, 0x49, 0xe4, 0x23, 0xe2, 0x9a, 0x2c, 0x0b, 0x26, 0x29, + 0x99, 0x0d, 0x04, 0x09, 0xce, 0x47, 0x66, 0x3f, 0x22, 0xa2, 0x6a, 0x0a, 0x66, 0xf6, 0x2c, 0x89, + 0x6c, 0xe0, 0x29, 0x62, 0x1f, 0xcb, 0x06, 0xe4, 0xb5, 0x16, 0x9d, 0x2b, 0xd5, 0x9f, 0x17, 0xf9, + 0x48, 0xf8, 0x7d, 0x02, 0xce, 0x8d, 0xcf, 0x81, 0x0f, 0x75, 0x03, 0x54, 0x21, 0x69, 0x0f, 0x49, + 0x80, 0x4a, 0x5e, 0x29, 0x8a, 0xe4, 0x11, 0x1d, 0xc0, 0x42, 0x4f, 0xef, 0xc8, 0x3d, 0xc9, 0xb7, + 0x31, 0x78, 0x4d, 0x7b, 0x79, 0xd4, 0x85, 0x69, 0xa6, 0xc3, 0xca, 0xc8, 0xde, 0xa8, 0x50, 0x1d, + 0xdb, 0xee, 0x06, 0x89, 0xdc, 0x1c, 0xe9, 0x6f, 0xbe, 0x39, 0xd0, 0x25, 0x28, 0xf6, 0xe5, 0xa1, + 0x64, 0x0f, 0x79, 0x44, 0x63, 0xa1, 0x0a, 0xfa, 0xf2, 0xb0, 0x3d, 0xa4, 0xe1, 0x4c, 0xf8, 0xa5, + 0xdf, 0x8a, 0xc1, 0x04, 0xff, 0x68, 0xad, 0xb8, 0x0f, 0x4b, 0xac, 0x18, 0xc1, 0xca, 0x18, 0x43, + 0xce, 0x10, 0x5c, 0x90, 0x23, 0xfe, 0x68, 0x6d, 0x28, 0xbc, 0xe1, 0x86, 0x58, 0xaf, 0x86, 0x41, + 0x57, 0x21, 0x45, 0xab, 0x1e, 0xb6, 0x1b, 0xcf, 0x8d, 0x5a, 0x81, 0x70, 0x89, 0x94, 0x47, 0x68, + 0x41, 0x3d, 0xba, 0x66, 0x99, 0x4b, 0xd3, 0x2f, 0x12, 0x6e, 0x80, 0x08, 0x94, 0x28, 0x8f, 0x78, + 0xa9, 0xde, 0x82, 0x45, 0x05, 0x77, 0x54, 0xe5, 0x9b, 0xae, 0xd4, 0x02, 0x97, 0x7e, 0xc4, 0x0b, + 0xf5, 0xe7, 0x02, 0xe4, 0x44, 0x6c, 0x19, 0xa4, 0x40, 0x40, 0xeb, 0x90, 0xc7, 0xc3, 0x0e, 0x36, + 0x6c, 0xa7, 0xa6, 0x1a, 0x5f, 0x9b, 0x32, 0xee, 0xa6, 0xc3, 0x49, 0x90, 0x96, 0x2b, 0x86, 0x6e, + 0x70, 0x50, 0x1d, 0x8d, 0x8f, 0xb9, 0xb8, 0x1f, 0x55, 0xbf, 0xe4, 0xa0, 0xea, 0x64, 0x24, 0xb0, + 0x62, 0x52, 0x21, 0x58, 0x7d, 0x83, 0xc3, 0xea, 0xd4, 0x94, 0x97, 0x05, 0x70, 0x75, 0x23, 0x80, + 0xab, 0xd3, 0x53, 0xa6, 0x19, 0x01, 0xac, 0x5f, 0x72, 0x80, 0x75, 0x66, 0xca, 0x17, 0x87, 0x90, + 0xf5, 0xed, 0x20, 0xb2, 0xce, 0x46, 0x44, 0x40, 0x47, 0x7a, 0x22, 0xb4, 0x7e, 0xdd, 0x07, 0xad, + 0x73, 0x91, 0x98, 0x96, 0x29, 0x1a, 0x83, 0xad, 0xdf, 0x0c, 0x60, 0xeb, 0xfc, 0x14, 0x3b, 0x4c, + 0x00, 0xd7, 0x1b, 0x7e, 0x70, 0x0d, 0x91, 0x18, 0x9d, 0xaf, 0x7b, 0x14, 0xba, 0x7e, 0xc5, 0x45, + 0xd7, 0x85, 0xc8, 0x36, 0x01, 0x9f, 0x4b, 0x18, 0x5e, 0xef, 0x8e, 0xc0, 0x6b, 0x06, 0x87, 0x9f, + 0x8e, 0x54, 0x31, 0x05, 0x5f, 0xef, 0x8e, 0xe0, 0xeb, 0xd2, 0x14, 0x85, 0x53, 0x00, 0xf6, 0xbb, + 0xe3, 0x01, 0x76, 0x34, 0x04, 0xe6, 0x9f, 0x39, 0x1b, 0xc2, 0x96, 0x22, 0x10, 0x76, 0x25, 0x12, + 0x0d, 0x32, 0xf5, 0x33, 0x43, 0xec, 0x83, 0x31, 0x10, 0x9b, 0x81, 0xe1, 0x2b, 0x91, 0xca, 0x67, + 0xc0, 0xd8, 0x07, 0x63, 0x30, 0xf6, 0xc2, 0x54, 0xb5, 0x53, 0x41, 0xf6, 0x66, 0x10, 0x64, 0xa3, + 0x29, 0x7b, 0x2c, 0x12, 0x65, 0x1f, 0x45, 0xa1, 0x6c, 0x86, 0x84, 0x9f, 0x8f, 0xd4, 0x38, 0x07, + 0xcc, 0xde, 0x1d, 0x81, 0xd9, 0x4b, 0x53, 0x3c, 0x6d, 0x56, 0x9c, 0xfd, 0x2c, 0x49, 0xc1, 0xa1, + 0x50, 0x4d, 0xaa, 0x45, 0x6c, 0x9a, 0xba, 0xc9, 0x11, 0x33, 0x1b, 0x08, 0x57, 0x08, 0xee, 0xf2, + 0xc2, 0xf2, 0x04, 0x4c, 0x4e, 0xab, 0x72, 0x5f, 0x28, 0x16, 0x7e, 0x1b, 0xf7, 0x64, 0x29, 0x5c, + 0xf1, 0x63, 0xb6, 0x3c, 0xc7, 0x6c, 0x3e, 0xa4, 0x9e, 0x08, 0x22, 0xf5, 0x15, 0x28, 0x90, 0x6a, + 0x3b, 0x04, 0xc2, 0x65, 0xc3, 0x05, 0xe1, 0x57, 0x61, 0x81, 0xa6, 0x4f, 0x86, 0xe7, 0x79, 0x89, + 0x9d, 0xa2, 0x15, 0x59, 0x85, 0xfc, 0xc0, 0xac, 0xc0, 0x6a, 0xed, 0x17, 0x60, 0xd1, 0xc7, 0xeb, + 0x56, 0xf1, 0x0c, 0x91, 0x56, 0x5d, 0xee, 0x35, 0x5e, 0xce, 0xff, 0x21, 0xee, 0x59, 0xc8, 0x43, + 0xef, 0xe3, 0x80, 0x76, 0xfc, 0x21, 0x01, 0xed, 0xc4, 0x37, 0x06, 0xda, 0x7e, 0x54, 0x92, 0x0c, + 0xa2, 0x92, 0x7f, 0xc6, 0xbd, 0x35, 0x71, 0x61, 0x73, 0x47, 0x57, 0x30, 0xc7, 0x09, 0xf4, 0x99, + 0x14, 0x28, 0x3d, 0xfd, 0x84, 0xa3, 0x01, 0xf2, 0x48, 0xb8, 0xdc, 0xdc, 0x99, 0xe7, 0xa9, 0xd1, + 0x85, 0x18, 0x69, 0x6a, 0x61, 0x0e, 0x31, 0xaa, 0x90, 0xbc, 0x8f, 0x59, 0xa6, 0x2b, 0x8a, 0xe4, + 0x91, 0xf0, 0x51, 0x27, 0xa3, 0xf9, 0xab, 0x28, 0xb2, 0x01, 0xba, 0x05, 0x79, 0xda, 0xfc, 0x97, + 0x74, 0xc3, 0xe2, 0x09, 0x29, 0x50, 0xe8, 0xb0, 0x1e, 0xff, 0xea, 0x1e, 0xe1, 0xd9, 0x35, 0x2c, + 0x31, 0x67, 0xf0, 0x27, 0x1f, 0x7a, 0xca, 0x07, 0x00, 0xfc, 0x05, 0xc8, 0x93, 0xaf, 0xb7, 0x0c, + 0xb9, 0x83, 0x69, 0x66, 0xc9, 0x8b, 0x1e, 0x41, 0xb8, 0x07, 0x68, 0x34, 0x4f, 0xa2, 0x16, 0x64, + 0xf0, 0x29, 0xd6, 0x6c, 0xb2, 0x6c, 0xc9, 0x70, 0x75, 0xc8, 0xeb, 0x22, 0xac, 0xd9, 0xeb, 0x35, + 0x62, 0xe4, 0x7f, 0x7c, 0xb9, 0x52, 0x65, 0xdc, 0xcf, 0xeb, 0x7d, 0xd5, 0xc6, 0x7d, 0xc3, 0x3e, + 0x13, 0xb9, 0xbc, 0xf0, 0xd7, 0x04, 0x81, 0xab, 0x81, 0xfc, 0x39, 0xd6, 0xb6, 0x8e, 0xcb, 0x27, + 0x7c, 0x6d, 0x8a, 0xd9, 0xec, 0x7d, 0x11, 0xe0, 0x44, 0xb6, 0xa4, 0x0f, 0x65, 0xcd, 0xc6, 0x0a, + 0x37, 0x7a, 0xfe, 0x44, 0xb6, 0xde, 0xa6, 0x04, 0xb2, 0xea, 0xe4, 0xe7, 0x81, 0x85, 0x15, 0x8e, + 0x42, 0xb2, 0x27, 0xb2, 0x75, 0x60, 0x61, 0xc5, 0x37, 0xcb, 0xec, 0x83, 0xcd, 0x32, 0x68, 0xe3, + 0x5c, 0xc8, 0xc6, 0x3e, 0x20, 0x99, 0xf7, 0x03, 0x49, 0x54, 0x87, 0x9c, 0x61, 0xaa, 0xba, 0xa9, + 0xda, 0x67, 0x74, 0x61, 0x92, 0xa2, 0x3b, 0x46, 0x97, 0xa1, 0xd4, 0xc7, 0x7d, 0x43, 0xd7, 0x7b, + 0x12, 0x0b, 0x36, 0x05, 0x2a, 0x5a, 0xe4, 0xc4, 0x26, 0x8d, 0x39, 0x1f, 0x27, 0xbc, 0xdd, 0xe7, + 0x35, 0x0c, 0x1e, 0xae, 0x79, 0x97, 0xc7, 0x98, 0xd7, 0x47, 0x21, 0x93, 0x08, 0xd9, 0xd7, 0x1d, + 0x7f, 0x5b, 0x06, 0x16, 0x7e, 0x42, 0x5b, 0x88, 0xc1, 0xda, 0x08, 0xed, 0xc3, 0x82, 0xbb, 0xf9, + 0xa5, 0x01, 0x0d, 0x0a, 0x8e, 0x3b, 0xcf, 0x1a, 0x3d, 0xaa, 0xa7, 0x41, 0xb2, 0x85, 0xde, 0x81, + 0xc7, 0x43, 0x91, 0xcd, 0x55, 0x9d, 0x98, 0x35, 0xc0, 0x3d, 0x16, 0x0c, 0x70, 0x8e, 0x6a, 0xcf, + 0x58, 0xc9, 0x07, 0xdc, 0x73, 0x5b, 0x50, 0x0e, 0x96, 0x79, 0x63, 0x97, 0xff, 0x32, 0x94, 0x4c, + 0x6c, 0xcb, 0xaa, 0x26, 0x05, 0xfa, 0x7e, 0x45, 0x46, 0xe4, 0xdd, 0xc4, 0x3d, 0x78, 0x6c, 0x6c, + 0xb9, 0x87, 0x5e, 0x86, 0xbc, 0x57, 0x29, 0xc6, 0x23, 0xc0, 0x93, 0xdb, 0x1a, 0xf2, 0x78, 0x85, + 0xdf, 0xc5, 0x3d, 0x95, 0xc1, 0x66, 0x53, 0x13, 0x32, 0x26, 0xb6, 0x06, 0x3d, 0xd6, 0xfe, 0x29, + 0x5f, 0x7f, 0x61, 0xb6, 0x42, 0x91, 0x50, 0x07, 0x3d, 0x5b, 0xe4, 0xc2, 0xc2, 0x3d, 0xc8, 0x30, + 0x0a, 0x2a, 0x40, 0xf6, 0x60, 0xe7, 0xce, 0xce, 0xee, 0xdb, 0x3b, 0xd5, 0x18, 0x02, 0xc8, 0xac, + 0x35, 0x1a, 0xcd, 0xbd, 0x76, 0x35, 0x8e, 0xf2, 0x90, 0x5e, 0x5b, 0xdf, 0x15, 0xdb, 0xd5, 0x04, + 0x21, 0x8b, 0xcd, 0xdb, 0xcd, 0x46, 0xbb, 0x9a, 0x44, 0x0b, 0x50, 0x62, 0xcf, 0xd2, 0xe6, 0xae, + 0x78, 0x77, 0xad, 0x5d, 0x4d, 0xf9, 0x48, 0xfb, 0xcd, 0x9d, 0x8d, 0xa6, 0x58, 0x4d, 0x0b, 0x2f, + 0xc2, 0xf9, 0xc8, 0xd2, 0xd2, 0xeb, 0x24, 0xc5, 0x7d, 0x9d, 0x24, 0xe1, 0xe7, 0x09, 0x82, 0xc4, + 0xa3, 0xea, 0x45, 0x74, 0x3b, 0x34, 0xf1, 0xeb, 0x73, 0x14, 0x9b, 0xa1, 0xd9, 0xa3, 0xa7, 0xa0, + 0x6c, 0xe2, 0x63, 0x6c, 0x77, 0xba, 0xac, 0x7e, 0x65, 0x09, 0xb3, 0x24, 0x96, 0x38, 0x95, 0x0a, + 0x59, 0x8c, 0xed, 0x7d, 0xdc, 0xb1, 0x25, 0x16, 0x8b, 0x98, 0xd3, 0xe5, 0x09, 0x1b, 0xa1, 0xee, + 0x33, 0xa2, 0xf0, 0xde, 0x5c, 0xb6, 0xcc, 0x43, 0x5a, 0x6c, 0xb6, 0xc5, 0x77, 0xaa, 0x49, 0x84, + 0xa0, 0x4c, 0x1f, 0xa5, 0xfd, 0x9d, 0xb5, 0xbd, 0xfd, 0xd6, 0x2e, 0xb1, 0xe5, 0x22, 0x54, 0x1c, + 0x5b, 0x3a, 0xc4, 0xb4, 0xf0, 0xa7, 0x04, 0x3c, 0x1e, 0x51, 0xed, 0xa2, 0x5b, 0x00, 0xf6, 0x50, + 0x32, 0x71, 0x47, 0x37, 0x95, 0x68, 0x27, 0x6b, 0x0f, 0x45, 0xca, 0x21, 0xe6, 0x6d, 0xfe, 0x64, + 0x4d, 0x68, 0x40, 0xa2, 0xd7, 0xb8, 0x52, 0x32, 0x2b, 0x67, 0xab, 0x5d, 0x1c, 0xd3, 0x3d, 0xc3, + 0x1d, 0xa2, 0x98, 0xda, 0x96, 0x2a, 0xa6, 0xfc, 0xe8, 0xee, 0xb8, 0xa0, 0x32, 0x63, 0xef, 0x7f, + 0xbe, 0x70, 0x92, 0x7e, 0xb0, 0x70, 0x22, 0xfc, 0x2a, 0xe9, 0x37, 0x6c, 0xb0, 0xb8, 0xdf, 0x85, + 0x8c, 0x65, 0xcb, 0xf6, 0xc0, 0xe2, 0x0e, 0xf7, 0xf2, 0xac, 0x48, 0x61, 0xd5, 0x79, 0xd8, 0xa7, + 0xe2, 0x22, 0x57, 0xf3, 0x7f, 0x7b, 0x5b, 0xc2, 0x4d, 0x28, 0x07, 0x8d, 0x13, 0xbd, 0x65, 0xbc, + 0x98, 0x93, 0x10, 0xde, 0xf5, 0xea, 0x2f, 0x5f, 0x97, 0x6f, 0x13, 0xca, 0x21, 0xb8, 0x14, 0x1f, + 0xc5, 0xf3, 0x5e, 0x97, 0xce, 0x85, 0x42, 0x62, 0xe9, 0xd4, 0x3f, 0x14, 0x7e, 0x1d, 0x87, 0x27, + 0x26, 0x00, 0x2a, 0xf4, 0x56, 0xc8, 0x11, 0x5e, 0x99, 0x07, 0x8e, 0xad, 0x32, 0x5a, 0xd0, 0x15, + 0x84, 0x1b, 0x50, 0xf4, 0xd3, 0x67, 0xb3, 0xc2, 0x4f, 0x93, 0x5e, 0x52, 0x08, 0x36, 0x18, 0x1f, + 0x5a, 0x25, 0x1a, 0x72, 0xc4, 0xc4, 0x9c, 0x8e, 0x38, 0xb6, 0x9a, 0x48, 0x3e, 0xba, 0x6a, 0x22, + 0xf5, 0x80, 0xd5, 0x84, 0x7f, 0x47, 0xa6, 0x83, 0x3b, 0x72, 0x24, 0xf1, 0x67, 0xc6, 0x24, 0xfe, + 0x77, 0x00, 0x7c, 0xe7, 0x67, 0x4b, 0x90, 0x36, 0xf5, 0x81, 0xa6, 0x50, 0x37, 0x49, 0x8b, 0x6c, + 0x80, 0x6e, 0x42, 0x9a, 0xb8, 0x9b, 0x63, 0xcc, 0xd1, 0xd0, 0x4c, 0xdc, 0xc5, 0xd7, 0x8e, 0x65, + 0xdc, 0x82, 0x0a, 0x68, 0xf4, 0x70, 0x22, 0xe2, 0x15, 0xaf, 0x07, 0x5f, 0xf1, 0x64, 0xe4, 0x31, + 0xc7, 0xf8, 0x57, 0x7d, 0x04, 0x69, 0xea, 0x1e, 0xa4, 0x00, 0xa2, 0x47, 0x71, 0x1c, 0x51, 0x93, + 0x67, 0xf4, 0x43, 0x00, 0xd9, 0xb6, 0x4d, 0xf5, 0x68, 0xe0, 0xbd, 0x60, 0x65, 0xbc, 0x7b, 0xad, + 0x39, 0x7c, 0xeb, 0x17, 0xb8, 0x9f, 0x2d, 0x79, 0xa2, 0x3e, 0x5f, 0xf3, 0x29, 0x14, 0x76, 0xa0, + 0x1c, 0x94, 0x75, 0x30, 0x20, 0xfb, 0x86, 0x20, 0x06, 0x64, 0x90, 0x9e, 0x63, 0x40, 0x17, 0x41, + 0x26, 0xd9, 0x91, 0x2b, 0x1d, 0x08, 0xff, 0x8e, 0x43, 0xd1, 0xef, 0x9d, 0xff, 0x6b, 0x30, 0x4a, + 0xf8, 0x38, 0x0e, 0x39, 0x77, 0xf2, 0x11, 0x47, 0x9e, 0x9e, 0xed, 0x12, 0xfe, 0x03, 0x3e, 0x76, + 0x86, 0x9a, 0x74, 0x4f, 0x66, 0x5f, 0x75, 0x2b, 0xae, 0xa8, 0xae, 0xb7, 0xdf, 0xd2, 0xce, 0x39, + 0x05, 0x2f, 0x30, 0x7f, 0xc6, 0xbf, 0x83, 0x94, 0x1a, 0xe8, 0xbb, 0x90, 0x91, 0x3b, 0x6e, 0xaf, + 0xbf, 0x3c, 0xa6, 0xf9, 0xeb, 0xb0, 0xae, 0xb6, 0x87, 0x6b, 0x94, 0x53, 0xe4, 0x12, 0xfc, 0xab, + 0x12, 0xee, 0xc9, 0xee, 0x1b, 0x44, 0x2f, 0xe3, 0x09, 0x86, 0xcd, 0x32, 0xc0, 0xc1, 0xce, 0xdd, + 0xdd, 0x8d, 0xad, 0xcd, 0xad, 0xe6, 0x06, 0xaf, 0xb9, 0x36, 0x36, 0x9a, 0x1b, 0xd5, 0x04, 0xe1, + 0x13, 0x9b, 0x77, 0x77, 0x0f, 0x9b, 0x1b, 0xd5, 0xa4, 0xf0, 0x2a, 0xe4, 0xdd, 0xd0, 0x83, 0x6a, + 0x90, 0x95, 0x15, 0xc5, 0xc4, 0x96, 0xc5, 0x8b, 0x51, 0x67, 0x48, 0x8f, 0xf4, 0xf5, 0x0f, 0xf9, + 0xb9, 0x66, 0x52, 0x64, 0x03, 0x41, 0x81, 0x4a, 0x28, 0x6e, 0xa1, 0x57, 0x21, 0x6b, 0x0c, 0x8e, + 0x24, 0xc7, 0x69, 0x43, 0x97, 0xee, 0x9c, 0x56, 0xc4, 0xe0, 0xa8, 0xa7, 0x76, 0xee, 0xe0, 0x33, + 0xc7, 0x4c, 0xc6, 0xe0, 0xe8, 0x0e, 0xf3, 0x6d, 0xf6, 0x96, 0x84, 0xff, 0x2d, 0x3f, 0x8e, 0x43, + 0xce, 0xd9, 0xab, 0xe8, 0x7b, 0x90, 0x77, 0x63, 0xa2, 0x7b, 0xd5, 0x23, 0x32, 0x98, 0x72, 0xfd, + 0x9e, 0x08, 0xba, 0x0a, 0x0b, 0x96, 0x7a, 0xa2, 0x39, 0xc7, 0x43, 0xac, 0xf7, 0x97, 0xa0, 0x9b, + 0xa6, 0xc2, 0x7e, 0xd8, 0x76, 0x1a, 0x56, 0xb7, 0x53, 0xb9, 0x64, 0x35, 0x75, 0x3b, 0x95, 0x4b, + 0x55, 0xd3, 0x24, 0x2d, 0x56, 0xc3, 0x81, 0xe3, 0xdb, 0xfc, 0x18, 0x52, 0x7e, 0x87, 0xf2, 0x3b, + 0xf3, 0xcd, 0x50, 0xfa, 0xfe, 0x57, 0x1c, 0x72, 0xce, 0x01, 0x14, 0x7a, 0xd1, 0x17, 0xc2, 0xca, + 0xe3, 0x3c, 0x96, 0x33, 0x7a, 0xd7, 0x09, 0x82, 0x53, 0x4a, 0xcc, 0x3f, 0xa5, 0xa8, 0x3b, 0x21, + 0xce, 0xed, 0x9c, 0xd4, 0xdc, 0xb7, 0x73, 0x9e, 0x07, 0x64, 0xeb, 0xb6, 0xdc, 0x93, 0x4e, 0x75, + 0x5b, 0xd5, 0x4e, 0x24, 0xe6, 0x21, 0x2c, 0xda, 0x54, 0xe9, 0x2f, 0x87, 0xf4, 0x87, 0x3d, 0xd7, + 0x59, 0x5c, 0x78, 0x38, 0xef, 0xed, 0x80, 0x73, 0x90, 0xe1, 0x08, 0x88, 0x5d, 0x0f, 0xe0, 0x23, + 0xf7, 0xc8, 0x32, 0xe5, 0x3b, 0xb2, 0xac, 0x43, 0xae, 0x8f, 0x6d, 0x99, 0x86, 0x4e, 0x96, 0x2d, + 0xdd, 0xf1, 0xd5, 0x57, 0xa0, 0xe0, 0xbb, 0xa8, 0x41, 0xa2, 0xe9, 0x4e, 0xf3, 0xed, 0x6a, 0xac, + 0x9e, 0xfd, 0xe4, 0xb3, 0x4b, 0xc9, 0x1d, 0xfc, 0x21, 0xd9, 0x68, 0x62, 0xb3, 0xd1, 0x6a, 0x36, + 0xee, 0x54, 0xe3, 0xf5, 0xc2, 0x27, 0x9f, 0x5d, 0xca, 0x8a, 0x98, 0x9e, 0x0f, 0x5d, 0x6d, 0x41, + 0xd1, 0xbf, 0x2a, 0xc1, 0x4d, 0x8d, 0xa0, 0xbc, 0x71, 0xb0, 0xb7, 0xbd, 0xd5, 0x58, 0x6b, 0x37, + 0xa5, 0xc3, 0xdd, 0x76, 0xb3, 0x1a, 0x47, 0x8f, 0xc3, 0xe2, 0xf6, 0xd6, 0x9b, 0xad, 0xb6, 0xd4, + 0xd8, 0xde, 0x6a, 0xee, 0xb4, 0xa5, 0xb5, 0x76, 0x7b, 0xad, 0x71, 0xa7, 0x9a, 0xb8, 0xfe, 0x9b, + 0x02, 0x54, 0xd6, 0xd6, 0x1b, 0x5b, 0x04, 0x00, 0xaa, 0x1d, 0x99, 0x86, 0x88, 0x06, 0xa4, 0x68, + 0xa7, 0x79, 0xe2, 0xa5, 0xdb, 0xfa, 0xe4, 0xd3, 0x43, 0xb4, 0x09, 0x69, 0xda, 0x84, 0x46, 0x93, + 0x6f, 0xe1, 0xd6, 0xa7, 0x1c, 0x27, 0x92, 0x8f, 0xa1, 0xbb, 0x68, 0xe2, 0xb5, 0xdc, 0xfa, 0xe4, + 0xd3, 0x45, 0xb4, 0x0d, 0x59, 0xa7, 0x47, 0x38, 0xed, 0x82, 0x6b, 0x7d, 0xea, 0x31, 0x1d, 0x99, + 0x1a, 0xeb, 0xe5, 0x4e, 0xbe, 0xb1, 0x5b, 0x9f, 0x72, 0xee, 0x88, 0xb6, 0x20, 0xc3, 0xdb, 0x28, + 0x53, 0x2e, 0xab, 0xd6, 0xa7, 0x1d, 0xb7, 0x21, 0x11, 0xf2, 0x5e, 0x97, 0x7c, 0xfa, 0x3d, 0xe4, + 0xfa, 0x0c, 0x47, 0xaa, 0xe8, 0x1e, 0x94, 0x82, 0xad, 0x99, 0xd9, 0x2e, 0xc4, 0xd6, 0x67, 0x3c, + 0xd8, 0x23, 0xfa, 0x83, 0x7d, 0x9a, 0xd9, 0x2e, 0xc8, 0xd6, 0x67, 0x3c, 0xe7, 0x43, 0xef, 0xc3, + 0xc2, 0x68, 0x1f, 0x65, 0xf6, 0xfb, 0xb2, 0xf5, 0x39, 0x4e, 0xfe, 0x50, 0x1f, 0xd0, 0x98, 0xfe, + 0xcb, 0x1c, 0xd7, 0x67, 0xeb, 0xf3, 0x1c, 0x04, 0x22, 0x05, 0x2a, 0xe1, 0x9e, 0xc6, 0xac, 0xd7, + 0x69, 0xeb, 0x33, 0x1f, 0x0a, 0xb2, 0xb7, 0x04, 0x01, 0xfe, 0xac, 0xd7, 0x6b, 0xeb, 0x33, 0x9f, + 0x11, 0xa2, 0x03, 0x00, 0x1f, 0x40, 0x9d, 0xe1, 0xba, 0x6d, 0x7d, 0x96, 0xd3, 0x42, 0x64, 0xc0, + 0xe2, 0x38, 0x60, 0x3a, 0xcf, 0xed, 0xdb, 0xfa, 0x5c, 0x87, 0x88, 0xc4, 0x9f, 0x83, 0x10, 0x73, + 0xb6, 0xdb, 0xb8, 0xf5, 0x19, 0x4f, 0x13, 0xd7, 0x9b, 0x9f, 0x7f, 0xb5, 0x1c, 0xff, 0xe2, 0xab, + 0xe5, 0xf8, 0xdf, 0xbf, 0x5a, 0x8e, 0x7f, 0xfa, 0xf5, 0x72, 0xec, 0x8b, 0xaf, 0x97, 0x63, 0x7f, + 0xf9, 0x7a, 0x39, 0xf6, 0xfd, 0xe7, 0x4e, 0x54, 0xbb, 0x3b, 0x38, 0x5a, 0xed, 0xe8, 0xfd, 0x6b, + 0xfe, 0x3f, 0x66, 0x8c, 0xfb, 0xb3, 0xc8, 0x51, 0x86, 0x66, 0xd3, 0x1b, 0xff, 0x0d, 0x00, 0x00, + 0xff, 0xff, 0x07, 0x27, 0x03, 0x70, 0x4c, 0x32, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5992,76 +5951,6 @@ func (m *RequestApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func (m *RequestExtendVote) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *RequestExtendVote) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *RequestExtendVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Vote != nil { - { - size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *RequestVerifyVoteExtension) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *RequestVerifyVoteExtension) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Vote != nil { - { - size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *RequestPrepareProposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -6213,6 +6102,76 @@ func (m *RequestProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *RequestExtendVote) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RequestExtendVote) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RequestExtendVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Vote != nil { + { + size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RequestVerifyVoteExtension) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RequestVerifyVoteExtension) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RequestVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Vote != nil { + { + size, err := m.Vote.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *RequestFinalizeBlock) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7490,69 +7449,6 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } -func (m *ResponseExtendVote) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ResponseExtendVote) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ResponseExtendVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.VoteExtension != nil { - { - size, err := m.VoteExtension.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *ResponseVerifyVoteExtension) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ResponseVerifyVoteExtension) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ResponseVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Status != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Status)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - func (m *ResponsePrepareProposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7583,7 +7479,7 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x32 + dAtA[i] = 0x2a } if len(m.ValidatorUpdates) > 0 { for iNdEx := len(m.ValidatorUpdates) - 1; iNdEx >= 0; iNdEx-- { @@ -7596,7 +7492,7 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x2a + dAtA[i] = 0x22 } } if len(m.TxResults) > 0 { @@ -7610,7 +7506,7 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 + dAtA[i] = 0x1a } } if len(m.AppHash) > 0 { @@ -7618,7 +7514,7 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) copy(dAtA[i:], m.AppHash) i = encodeVarintTypes(dAtA, i, uint64(len(m.AppHash))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 } if len(m.TxRecords) > 0 { for iNdEx := len(m.TxRecords) - 1; iNdEx >= 0; iNdEx-- { @@ -7631,14 +7527,9 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0xa } } - if m.ModifiedTxStatus != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.ModifiedTxStatus)) - i-- - dAtA[i] = 0x8 - } return len(dAtA) - i, nil } @@ -7717,6 +7608,69 @@ func (m *ResponseProcessProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *ResponseExtendVote) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResponseExtendVote) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResponseExtendVote) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.VoteExtension != nil { + { + size, err := m.VoteExtension.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResponseVerifyVoteExtension) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResponseVerifyVoteExtension) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResponseVerifyVoteExtension) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Status != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *ResponseFinalizeBlock) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8908,32 +8862,6 @@ func (m *RequestApplySnapshotChunk) Size() (n int) { return n } -func (m *RequestExtendVote) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Vote != nil { - l = m.Vote.Size() - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - -func (m *RequestVerifyVoteExtension) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Vote != nil { - l = m.Vote.Size() - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - func (m *RequestPrepareProposal) Size() (n int) { if m == nil { return 0 @@ -8995,6 +8923,32 @@ func (m *RequestProcessProposal) Size() (n int) { return n } +func (m *RequestExtendVote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Vote != nil { + l = m.Vote.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *RequestVerifyVoteExtension) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Vote != nil { + l = m.Vote.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *RequestFinalizeBlock) Size() (n int) { if m == nil { return 0 @@ -9615,40 +9569,12 @@ func (m *ResponseApplySnapshotChunk) Size() (n int) { return n } -func (m *ResponseExtendVote) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.VoteExtension != nil { - l = m.VoteExtension.Size() - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - -func (m *ResponseVerifyVoteExtension) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Status != 0 { - n += 1 + sovTypes(uint64(m.Status)) - } - return n -} - func (m *ResponsePrepareProposal) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.ModifiedTxStatus != 0 { - n += 1 + sovTypes(uint64(m.ModifiedTxStatus)) - } if len(m.TxRecords) > 0 { for _, e := range m.TxRecords { l = e.Size() @@ -9710,6 +9636,31 @@ func (m *ResponseProcessProposal) Size() (n int) { return n } +func (m *ResponseExtendVote) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VoteExtension != nil { + l = m.VoteExtension.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *ResponseVerifyVoteExtension) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Status != 0 { + n += 1 + sovTypes(uint64(m.Status)) + } + return n +} + func (m *ResponseFinalizeBlock) Size() (n int) { if m == nil { return 0 @@ -12310,178 +12261,6 @@ func (m *RequestApplySnapshotChunk) Unmarshal(dAtA []byte) error { } return nil } -func (m *RequestExtendVote) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: RequestExtendVote: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: RequestExtendVote: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Vote", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Vote == nil { - m.Vote = &types1.Vote{} - } - if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: RequestVerifyVoteExtension: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: RequestVerifyVoteExtension: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Vote", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.Vote == nil { - m.Vote = &types1.Vote{} - } - if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -12933,6 +12712,178 @@ func (m *RequestProcessProposal) Unmarshal(dAtA []byte) error { } return nil } +func (m *RequestExtendVote) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RequestExtendVote: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RequestExtendVote: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Vote", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Vote == nil { + m.Vote = &types1.Vote{} + } + if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RequestVerifyVoteExtension) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RequestVerifyVoteExtension: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RequestVerifyVoteExtension: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Vote", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Vote == nil { + m.Vote = &types1.Vote{} + } + if err := m.Vote.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RequestFinalizeBlock) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -16140,161 +16091,6 @@ func (m *ResponseApplySnapshotChunk) Unmarshal(dAtA []byte) error { } return nil } -func (m *ResponseExtendVote) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ResponseExtendVote: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ResponseExtendVote: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.VoteExtension == nil { - m.VoteExtension = &types1.VoteExtension{} - } - if err := m.VoteExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ResponseVerifyVoteExtension) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ResponseVerifyVoteExtension: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ResponseVerifyVoteExtension: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) - } - m.Status = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Status |= ResponseVerifyVoteExtension_VerifyStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -16325,25 +16121,6 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ModifiedTxStatus", wireType) - } - m.ModifiedTxStatus = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ModifiedTxStatus |= ResponsePrepareProposal_ModifiedTxStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxRecords", wireType) } @@ -16377,7 +16154,7 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) } @@ -16411,7 +16188,7 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { m.AppHash = []byte{} } iNdEx = postIndex - case 4: + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxResults", wireType) } @@ -16445,7 +16222,7 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ValidatorUpdates", wireType) } @@ -16479,7 +16256,7 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ConsensusParamUpdates", wireType) } @@ -16743,6 +16520,161 @@ func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResponseExtendVote) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResponseExtendVote: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResponseExtendVote: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.VoteExtension == nil { + m.VoteExtension = &types1.VoteExtension{} + } + if err := m.VoteExtension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResponseVerifyVoteExtension) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResponseVerifyVoteExtension: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResponseVerifyVoteExtension: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= ResponseVerifyVoteExtension_VerifyStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/cmd/tendermint/commands/debug/debug.go b/cmd/tendermint/commands/debug/debug.go index 478a03d55..7fd5b030f 100644 --- a/cmd/tendermint/commands/debug/debug.go +++ b/cmd/tendermint/commands/debug/debug.go @@ -2,6 +2,7 @@ package debug import ( "github.com/spf13/cobra" + "github.com/tendermint/tendermint/libs/log" ) diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index f218a5cf1..ab7a2baf3 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -317,9 +317,20 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_UNMODIFIED, + + trs := make([]*abci.TxRecord, 0, len(req.Txs)) + var totalBytes int64 + for _, tx := range req.Txs { + totalBytes += int64(len(tx)) + if totalBytes > req.MaxTxBytes { + break + } + trs = append(trs, &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + }) } + return abci.ResponsePrepareProposal{TxRecords: trs} } func (app *CounterApplication) ProcessProposal( diff --git a/internal/consensus/mocks/cons_sync_reactor.go b/internal/consensus/mocks/cons_sync_reactor.go index 5ac592f0d..b254fc701 100644 --- a/internal/consensus/mocks/cons_sync_reactor.go +++ b/internal/consensus/mocks/cons_sync_reactor.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + state "github.com/tendermint/tendermint/internal/state" ) diff --git a/internal/consensus/peer_state_test.go b/internal/consensus/peer_state_test.go index 2b5712455..97be569ff 100644 --- a/internal/consensus/peer_state_test.go +++ b/internal/consensus/peer_state_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/types" diff --git a/internal/consensus/state.go b/internal/consensus/state.go index b96c9cecb..670d0c42b 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1415,7 +1415,11 @@ func (cs *State) createProposalBlock(ctx context.Context) (*types.Block, error) proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(ctx, cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) + ret, err := cs.blockExec.CreateProposalBlock(ctx, cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) + if err != nil { + panic(err) + } + return ret, nil } // Enter: `timeoutPropose` after entering Propose. diff --git a/internal/evidence/mocks/block_store.go b/internal/evidence/mocks/block_store.go index ef3346b2a..5ea8d8344 100644 --- a/internal/evidence/mocks/block_store.go +++ b/internal/evidence/mocks/block_store.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + types "github.com/tendermint/tendermint/types" ) diff --git a/internal/mempool/mempool_bench_test.go b/internal/mempool/mempool_bench_test.go index 843e42e87..cc3ff7368 100644 --- a/internal/mempool/mempool_bench_test.go +++ b/internal/mempool/mempool_bench_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/require" + abciclient "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/example/kvstore" "github.com/tendermint/tendermint/libs/log" diff --git a/internal/proxy/client.go b/internal/proxy/client.go index 7444c841e..2af1b1021 100644 --- a/internal/proxy/client.go +++ b/internal/proxy/client.go @@ -8,6 +8,7 @@ import ( "time" "github.com/go-kit/kit/metrics" + abciclient "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/example/kvstore" "github.com/tendermint/tendermint/abci/types" diff --git a/internal/proxy/client_test.go b/internal/proxy/client_test.go index c3991a8e2..057177a60 100644 --- a/internal/proxy/client_test.go +++ b/internal/proxy/client_test.go @@ -14,6 +14,8 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "gotest.tools/assert" + abciclient "github.com/tendermint/tendermint/abci/client" abcimocks "github.com/tendermint/tendermint/abci/client/mocks" "github.com/tendermint/tendermint/abci/example/kvstore" @@ -21,7 +23,6 @@ import ( "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmrand "github.com/tendermint/tendermint/libs/rand" - "gotest.tools/assert" ) //---------------------------------------- diff --git a/internal/state/execution.go b/internal/state/execution.go index bd800ae8e..b28288f49 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -121,22 +121,15 @@ func (blockExec *BlockExecutor) CreateProposalBlock( // transaction causing an error. // // Also, the App can simply skip any transaction that could cause any kind of trouble. - // Either way, we can not recover in a meaningful way, unless we skip proposing - // this block, repair what caused the error and try again. Hence, we panic on - // purpose for now. - panic(err) - } - if rpp.IsTxStatusUnknown() { - panic(fmt.Sprintf("PrepareProposal responded with ModifiedTxStatus %s", rpp.ModifiedTxStatus.String())) - } - - if !rpp.IsTxStatusModified() { - return block, nil + // Either way, we cannot recover in a meaningful way, unless we skip proposing + // this block, repair what caused the error and try again. Hence, we return an + // error for now (the production code calling this function is expected to panic). + return nil, err } txrSet := types.NewTxRecordSet(rpp.TxRecords) if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { - panic(fmt.Errorf("ResponsePrepareProposal validation: %w", err)) + return nil, err } for _, rtx := range txrSet.RemovedTxs() { diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index 9c5042645..3093e2c53 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -2,6 +2,7 @@ package state_test import ( "context" + "errors" "testing" "time" @@ -11,6 +12,7 @@ import ( dbm "github.com/tendermint/tm-db" abciclient "github.com/tendermint/tendermint/abci/client" + abciclientmocks "github.com/tendermint/tendermint/abci/client/mocks" abci "github.com/tendermint/tendermint/abci/types" abcimocks "github.com/tendermint/tendermint/abci/types/mocks" "github.com/tendermint/tendermint/crypto" @@ -271,7 +273,7 @@ func TestFinalizeBlockByzantineValidators(t *testing.T) { func TestProcessProposal(t *testing.T) { const height = 2 - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -617,9 +619,7 @@ func TestEmptyPrepareProposal(t *testing.T) { require.NoError(t, eventBus.Start(ctx)) app := abcimocks.NewBaseMock() - app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_UNMODIFIED, - }, nil) + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{}) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) err := proxyApp.Start(ctx) @@ -656,9 +656,10 @@ func TestEmptyPrepareProposal(t *testing.T) { require.NoError(t, err) } -// TestPrepareProposalPanicOnInvalid tests that the block creation logic panics -// if the ResponsePrepareProposal returned from the application is invalid. -func TestPrepareProposalPanicOnInvalid(t *testing.T) { +// TestPrepareProposalErrorOnNonExistingRemoved tests that the block creation logic returns +// an error if the ResponsePrepareProposal returned from the application marks +// a transaction as REMOVED that was not present in the original proposal. +func TestPrepareProposalErrorOnNonExistingRemoved(t *testing.T) { const height = 2 ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -680,7 +681,6 @@ func TestPrepareProposalPanicOnInvalid(t *testing.T) { // create an invalid ResponsePrepareProposal rpp := abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_MODIFIED, TxRecords: []*abci.TxRecord{ { Action: abci.TxRecord_REMOVED, @@ -688,7 +688,7 @@ func TestPrepareProposalPanicOnInvalid(t *testing.T) { }, }, } - app.On("PrepareProposal", mock.Anything).Return(rpp, nil) + app.On("PrepareProposal", mock.Anything).Return(rpp) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) @@ -707,10 +707,9 @@ func TestPrepareProposalPanicOnInvalid(t *testing.T) { ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) - require.Panics(t, - func() { - blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) //nolint:errcheck - }) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + require.Nil(t, block) + require.ErrorContains(t, err, "new transaction incorrectly marked as removed") mp.AssertExpectations(t) } @@ -733,7 +732,7 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) @@ -744,9 +743,8 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_MODIFIED, - TxRecords: trs, - }, nil) + TxRecords: trs, + }) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) @@ -794,7 +792,7 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs[2:])) @@ -804,9 +802,8 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_MODIFIED, - TxRecords: trs, - }, nil) + TxRecords: trs, + }) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) @@ -851,7 +848,7 @@ func TestPrepareProposalReorderTxs(t *testing.T) { evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + txs := factory.MakeNTxs(height, 10) mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) @@ -861,9 +858,8 @@ func TestPrepareProposalReorderTxs(t *testing.T) { app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_MODIFIED, - TxRecords: trs, - }, nil) + TxRecords: trs, + }) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) @@ -892,10 +888,9 @@ func TestPrepareProposalReorderTxs(t *testing.T) { } -// TestPrepareProposalModifiedTxStatusFalse tests that CreateBlock correctly ignores -// the ResponsePrepareProposal TxRecords if ResponsePrepareProposal does not -// set ModifiedTxStatus to true. -func TestPrepareProposalModifiedTxStatusFalse(t *testing.T) { +// TestPrepareProposalErrorOnTooManyTxs tests that the block creation logic returns +// an error if the ResponsePrepareProposal returned from the application is invalid. +func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) { const height = 2 ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -905,29 +900,26 @@ func TestPrepareProposalModifiedTxStatusFalse(t *testing.T) { require.NoError(t, eventBus.Start(ctx)) state, stateDB, privVals := makeState(t, 1, height) + // limit max block size + state.ConsensusParams.Block.MaxBytes = 60 * 1024 stateStore := sm.NewStore(stateDB) evpool := &mocks.EvidencePool{} evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) - txs := factory.MakeTenTxs(height) + const nValidators = 1 + var bytesPerTx int64 = 3 + maxDataBytes := types.MaxDataBytes(state.ConsensusParams.Block.MaxBytes, 0, nValidators) + txs := factory.MakeNTxs(height, maxDataBytes/bytesPerTx+2) // +2 so that tx don't fit mp := &mpmocks.Mempool{} mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) trs := txsToTxRecords(types.Txs(txs)) - trs = append(trs[len(trs)/2:], trs[:len(trs)/2]...) - trs = trs[1:] - trs[0].Action = abci.TxRecord_REMOVED - trs[1] = &abci.TxRecord{ - Tx: []byte("new"), - Action: abci.TxRecord_ADDED, - } app := abcimocks.NewBaseMock() app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ - ModifiedTxStatus: abci.ResponsePrepareProposal_UNMODIFIED, - TxRecords: trs, - }, nil) + TxRecords: trs, + }) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) @@ -946,11 +938,62 @@ func TestPrepareProposalModifiedTxStatusFalse(t *testing.T) { ) pa, _ := state.Validators.GetByIndex(0) commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + require.Nil(t, block) + require.ErrorContains(t, err, "transaction data size exceeds maximum") + + mp.AssertExpectations(t) +} + +// TestPrepareProposalErrorOnPrepareProposalError tests when the client returns an error +// upon calling PrepareProposal on it. +func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) { + const height = 2 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.NewNopLogger() + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + state, stateDB, privVals := makeState(t, 1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeNTxs(height, 10) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + cm := &abciclientmocks.Client{} + cm.On("IsRunning").Return(true) + cm.On("Error").Return(nil) + cm.On("Start", mock.Anything).Return(nil).Once() + cm.On("Wait").Return(nil).Once() + cm.On("PrepareProposal", mock.Anything, mock.Anything).Return(nil, errors.New("an injected error")).Once() + + proxyApp := proxy.New(cm, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) require.NoError(t, err) - for i, tx := range block.Data.Txs { - require.Equal(t, txs[i], tx) - } + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp, + mp, + evpool, + nil, + eventBus, + sm.NopMetrics(), + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + require.Nil(t, block) + require.ErrorContains(t, err, "an injected error") mp.AssertExpectations(t) } diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 1e0187247..6e97abccb 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -62,7 +62,7 @@ func makeAndApplyGoodBlock( evidence []types.Evidence, ) (sm.State, types.BlockID) { t.Helper() - block := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr) partSet, err := block.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) diff --git a/internal/state/indexer/mocks/event_sink.go b/internal/state/indexer/mocks/event_sink.go index d5555a417..6173480dd 100644 --- a/internal/state/indexer/mocks/event_sink.go +++ b/internal/state/indexer/mocks/event_sink.go @@ -6,6 +6,7 @@ import ( context "context" mock "github.com/stretchr/testify/mock" + indexer "github.com/tendermint/tendermint/internal/state/indexer" query "github.com/tendermint/tendermint/internal/pubsub/query" diff --git a/internal/state/mocks/evidence_pool.go b/internal/state/mocks/evidence_pool.go index 04e8be7bc..b4f42e580 100644 --- a/internal/state/mocks/evidence_pool.go +++ b/internal/state/mocks/evidence_pool.go @@ -6,6 +6,7 @@ import ( context "context" mock "github.com/stretchr/testify/mock" + state "github.com/tendermint/tendermint/internal/state" types "github.com/tendermint/tendermint/types" diff --git a/internal/state/mocks/store.go b/internal/state/mocks/store.go index 02c69d3e0..b7a58e415 100644 --- a/internal/state/mocks/store.go +++ b/internal/state/mocks/store.go @@ -4,6 +4,7 @@ package mocks import ( mock "github.com/stretchr/testify/mock" + state "github.com/tendermint/tendermint/internal/state" tendermintstate "github.com/tendermint/tendermint/proto/tendermint/state" diff --git a/internal/state/test/factory/block.go b/internal/state/test/factory/block.go index 14f49e2d5..1b3351363 100644 --- a/internal/state/test/factory/block.go +++ b/internal/state/test/factory/block.go @@ -45,7 +45,7 @@ func MakeBlocks(ctx context.Context, t *testing.T, n int, state *sm.State, privV func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block { return state.MakeBlock( height, - factory.MakeTenTxs(state.LastBlockHeight), + factory.MakeNTxs(state.LastBlockHeight, 10), c, nil, state.Validators.GetProposer().Address, diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index e111ec6cc..5e164f447 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -338,7 +338,7 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) currentBytes += int64(len(newEv.Bytes())) } - block := state.MakeBlock(height, testfactory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, testfactory.MakeNTxs(height, 10), lastCommit, evidence, proposerAddr) err := blockExec.ValidateBlock(ctx, state, block) if assert.Error(t, err) { diff --git a/internal/statesync/mocks/state_provider.go b/internal/statesync/mocks/state_provider.go index b8d681631..b19a6787f 100644 --- a/internal/statesync/mocks/state_provider.go +++ b/internal/statesync/mocks/state_provider.go @@ -6,6 +6,7 @@ import ( context "context" mock "github.com/stretchr/testify/mock" + state "github.com/tendermint/tendermint/internal/state" types "github.com/tendermint/tendermint/types" diff --git a/internal/test/factory/tx.go b/internal/test/factory/tx.go index 035308349..725f3c720 100644 --- a/internal/test/factory/tx.go +++ b/internal/test/factory/tx.go @@ -2,10 +2,10 @@ package factory import "github.com/tendermint/tendermint/types" -func MakeTenTxs(height int64) []types.Tx { - txs := make([]types.Tx, 10) +func MakeNTxs(height, n int64) []types.Tx { + txs := make([]types.Tx, n) for i := range txs { - txs[i] = types.Tx([]byte{byte(height), byte(i)}) + txs[i] = types.Tx([]byte{byte(height), byte(i / 256), byte(i % 256)}) } return txs } diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 53742c41e..03bf9a9e8 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -316,18 +316,11 @@ message ResponseApplySnapshotChunk { } message ResponsePrepareProposal { - ModifiedTxStatus modified_tx_status = 1; - repeated TxRecord tx_records = 2; - bytes app_hash = 3; - repeated ExecTxResult tx_results = 4; - repeated ValidatorUpdate validator_updates = 5; - tendermint.types.ConsensusParams consensus_param_updates = 6; - - enum ModifiedTxStatus { - UNKNOWN = 0; - UNMODIFIED = 1; - MODIFIED = 2; - } + repeated TxRecord tx_records = 1; + bytes app_hash = 2; + repeated ExecTxResult tx_results = 3; + repeated ValidatorUpdate validator_updates = 4; + tendermint.types.ConsensusParams consensus_param_updates = 5; } message ResponseProcessProposal { diff --git a/proto/tendermint/abci/types.proto.intermediate b/proto/tendermint/abci/types.proto.intermediate index cf77d25ea..226cb21fc 100644 --- a/proto/tendermint/abci/types.proto.intermediate +++ b/proto/tendermint/abci/types.proto.intermediate @@ -313,18 +313,11 @@ message ResponseApplySnapshotChunk { } message ResponsePrepareProposal { - ModifiedTxStatus modified_tx_status = 1; - repeated TxRecord tx_records = 2; - bytes app_hash = 3; - repeated ExecTxResult tx_results = 4; - repeated ValidatorUpdate validator_updates = 5; - tendermint.types.ConsensusParams consensus_param_updates = 6; - - enum ModifiedTxStatus { - UNKNOWN = 0; - UNMODIFIED = 1; - MODIFIED = 2; - } + repeated TxRecord tx_records = 1; + bytes app_hash = 2; + repeated ExecTxResult tx_results = 3; + repeated ValidatorUpdate validator_updates = 4; + tendermint.types.ConsensusParams consensus_param_updates = 5; } message ResponseProcessProposal { diff --git a/spec/abci++/abci++_methods_002_draft.md b/spec/abci++/abci++_methods_002_draft.md index 545f6cde0..2799e789b 100644 --- a/spec/abci++/abci++_methods_002_draft.md +++ b/spec/abci++/abci++_methods_002_draft.md @@ -298,7 +298,6 @@ title: Methods | Name | Type | Description | Field Number | |-------------------------|--------------------------------------------------|---------------------------------------------------------------------------------------------|--------------| - | modified_tx_status | [TxModifiedStatus](#TxModifiedStatus) | `enum` signaling if the application has made changes to the list of transactions. | 1 | | tx_records | repeated [TxRecord](#txrecord) | Possibly modified list of transactions that have been picked as part of the proposed block. | 2 | | app_hash | bytes | The Merkle root hash of the application state. | 3 | | tx_results | repeated [ExecTxResult](#txresult) | List of structures containing the data resulting from executing the transactions | 4 | @@ -311,19 +310,15 @@ title: Methods * The header contains the height, timestamp, and more - it exactly matches the Tendermint block header. * `RequestPrepareProposal` contains a preliminary set of transactions `txs` that Tendermint considers to be a good block proposal, called _raw proposal_. The Application can modify this set via `ResponsePrepareProposal.tx_records` (see [TxRecord](#txrecord)). - * In this case, the Application should set `ResponsePrepareProposal.modified_tx_status` to `MODIFIED`. * The Application _can_ reorder, remove or add transactions to the raw proposal. Let `tx` be a transaction in `txs`: * If the Application considers that `tx` should not be proposed in this block, e.g., there are other transactions with higher priority, then it should not include it in `tx_records`. In this case, Tendermint won't remove `tx` from the mempool. The Application should be extra-careful, as abusing this feature may cause transactions to stay forever in the mempool. * If the Application considers that a `tx` should not be included in the proposal and removed from the mempool, then the Application should include it in `tx_records` and _mark_ it as `REMOVED`. In this case, Tendermint will remove `tx` from the mempool. * If the Application wants to add a new transaction, then the Application should include it in `tx_records` and _mark_ it as `ADD`. In this case, Tendermint will add it to the mempool. * The Application should be aware that removing and adding transactions may compromise _traceability_. > Consider the following example: the Application transforms a client-submitted transaction `t1` into a second transaction `t2`, i.e., the Application asks Tendermint to remove `t1` and add `t2` to the mempool. If a client wants to eventually check what happened to `t1`, it will discover that `t_1` is not in the mempool or in a committed block, getting the wrong idea that `t_1` did not make it into a block. Note that `t_2` _will be_ in a committed block, but unless the Application tracks this information, no component will be aware of it. Thus, if the Application wants traceability, it is its responsability to support it. For instance, the Application could attach to a transformed transaction a list with the hashes of the transactions it derives from. - * If the Application does not modify the preliminary set of transactions `txs`, then it sets `ResponsePrepareProposal.modified_tx_status` to `UNMODIFIED`. In this case, Tendermint will ignore the contents of `ResponsePrepareProposal.tx_records`. * Tendermint MAY include a list of transactions in `RequestPrepareProposal.txs` whose total size in bytes exceeds `RequestPrepareProposal.max_tx_bytes`. - Therefore, if the size of `RequestPrepareProposal.txs` is greater than `RequestPrepareProposal.max_tx_bytes`: - * the Application MUST make sure that the `RequestPrepareProposal.max_tx_bytes` limit is respected by those - transaction records returned in `ResponsePrepareProposal.tx_records` that are marked as `UNMODIFIED` or `ADDED`. - * the Application MUST set `ResponsePrepareProposal.modified_tx_status` to `MODIFIED`. Tendermint will panic otherwise. + Therefore, if the size of `RequestPrepareProposal.txs` is greater than `RequestPrepareProposal.max_tx_bytes`, the Application MUST make sure that the + `RequestPrepareProposal.max_tx_bytes` limit is respected by those transaction records returned in `ResponsePrepareProposal.tx_records` that are marked as `UNMODIFIED` or `ADDED`. * In same-block execution mode, the Application must provide values for `ResponsePrepareProposal.app_hash`, `ResponsePrepareProposal.tx_results`, `ResponsePrepareProposal.validator_updates`, and `ResponsePrepareProposal.consensus_param_updates`, as a result of fully executing the block. @@ -413,7 +408,7 @@ Note that, if _p_ has a non-`nil` _validValue_, Tendermint will use it as propos | Name | Type | Description | Field Number | |-------------------------|--------------------------------------------------|-----------------------------------------------------------------------------------|--------------| - | status | [ProposalStatus](#ProposalStatus) | `enum` that signals if the application finds the proposal valid. | 1 | + | status | [ProposalStatus](#proposalstatus) | `enum` that signals if the application finds the proposal valid. | 1 | | app_hash | bytes | The Merkle root hash of the application state. | 2 | | tx_results | repeated [ExecTxResult](#txresult) | List of structures containing the data resulting from executing the transactions. | 3 | | validator_updates | repeated [ValidatorUpdate](#validatorupdate) | Changes to validator set (set voting power to 0 to remove). | 4 | @@ -539,7 +534,7 @@ a [CanonicalVoteExtension](#canonicalvoteextension) field in the `precommit nil` | Name | Type | Description | Field Number | |--------|-------------------------------|----------------------------------------------------------------|--------------| - | status | [VerifyStatus](#VerifyStatus) | `enum` signaling if the application accepts the vote extension | 1 | + | status | [VerifyStatus](#verifystatus) | `enum` signaling if the application accepts the vote extension | 1 | * **Usage**: * `RequestVerifyVoteExtension.vote_extension` can be an empty byte array. The Application's interpretation of it should be @@ -832,7 +827,7 @@ Most of the data structures used in ABCI are shared [common data structures](../ | info | string | Additional information. **May be non-deterministic.** | 4 | | gas_wanted | int64 | Amount of gas requested for transaction. | 5 | | gas_used | int64 | Amount of gas consumed by transaction. | 6 | - | events | repeated [Event](abci++_basic_concepts_002_draft.md#events) | Type & Key-Value events for indexing transactions (e.g. by account). | 7 | + | events | repeated [Event](abci++_basic_concepts_002_draft.md#events) | Type & Key-Value events for indexing transactions (e.g. by account). | 7 | | codespace | string | Namespace for the `code`. | 8 | ### TxAction @@ -852,6 +847,7 @@ enum TxAction { * If `Action` is `ADDED`, Tendermint includes the transaction in the proposal. The transaction is _not_ added to the mempool. * If `Action` is `REMOVED`, Tendermint excludes the transaction from the proposal. The transaction is also removed from the mempool if it exists, similar to `CheckTx` returning _false_. + ### TxRecord * **Fields**: @@ -872,26 +868,10 @@ enum ProposalStatus { ``` * **Usage**: - * Used within the [ProcessProposal](#ProcessProposal) response. - * If `Status` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash. - * If `Status` is `ACCEPT`, Tendermint accepts the proposal and will issue a Prevote message for it. - * If `Status` is `REJECT`, Tendermint rejects the proposal and will issue a Prevote for `nil` instead. - -### TxModifiedStatus - -```proto -enum ModifiedTxStatus { - UNKNOWN = 0; // Unknown status. Returning this from the application is always an error. - UNMODIFIED = 1; // Status that signals the application has modified the returned list of transactions. - MODIFIED = 2; // Status that signals that the application has not modified the list of transactions. -} -``` - -* **Usage**: - * Used within the [PrepareProposal](#PrepareProposal) response. - * If `TxModifiedStatus` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash. - * If `TxModifiedStatus` is `UNMODIFIED`, Tendermint will ignore the contents of the `PrepareProposal` response and use the transactions originally passed to the application during `PrepareProposal`. - * If `TxModifiedStatus` is `MODIFIED`, Tendermint will update the block proposal using the contents of the `PrepareProposal` response returned by the application. + * Used within the [ProcessProposal](#processproposal) response. + * If `Status` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash. + * If `Status` is `ACCEPT`, Tendermint accepts the proposal and will issue a Prevote message for it. + * If `Status` is `REJECT`, Tendermint rejects the proposal and will issue a Prevote for `nil` instead. ### VerifyStatus @@ -904,10 +884,10 @@ enum VerifyStatus { ``` * **Usage**: - * Used within the [VerifyVoteExtension](#VerifyVoteExtension) response. - * If `Status` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash. - * If `Status` is `ACCEPT`, Tendermint will accept the vote as valid. - * If `Status` is `REJECT`, Tendermint will reject the vote as invalid. + * Used within the [VerifyVoteExtension](#verifyvoteextension) response. + * If `Status` is `UNKNOWN`, a problem happened in the Application. Tendermint will assume the application is faulty and crash. + * If `Status` is `ACCEPT`, Tendermint will accept the vote as valid. + * If `Status` is `REJECT`, Tendermint will reject the vote as invalid. ### CanonicalVoteExtension diff --git a/spec/abci++/abci++_tmint_expected_behavior_002_draft.md b/spec/abci++/abci++_tmint_expected_behavior_002_draft.md index 2616da4fa..778689450 100644 --- a/spec/abci++/abci++_tmint_expected_behavior_002_draft.md +++ b/spec/abci++/abci++_tmint_expected_behavior_002_draft.md @@ -202,14 +202,17 @@ to undergo any changes in their implementation. As for the new methods: -* `PrepareProposal` should check whether the size of transactions exceeds the byte limit. - * If it does: remove transactions at the end of the list until the total byte size conforms to the limit, - then set `ResponsePrepareProposal.modified_tx_status` to `MODIFIED` and return. - * Else, set `ResponsePrepareProposal.modified_tx_status` to `UNMODIFIED` and return. -* `ProcessProposal` should set `ResponseProcessProposal.accept` to _true_ and return. -* `ExtendVote` should set `ResponseExtendVote.extension` to an empty byte array and return. -* `VerifyVoteExtension` should set `ResponseVerifyVoteExtension.accept` to _true_ if the extension is an empty byte array +* `PrepareProposal` must create a list of [TxRecord](./abci++_methods_002_draft.md#txrecord) each containing a + transaction passed in `RequestPrepareProposal.txs`, in the same other. The field `action` must be set to `UNMODIFIED` + for all [TxRecord](./abci++_methods_002_draft.md#txrecord) elements in the list. + The Application must check whether the size of all transactions exceeds the byte limit + (`RequestPrepareProposal.max_tx_bytes`). If so, the Application must remove transactions at the end of the list + until the total byte size is at or below the limit. +* `ProcessProposal` must set `ResponseProcessProposal.accept` to _true_ and return. +* `ExtendVote` is to set `ResponseExtendVote.extension` to an empty byte array and return. +* `VerifyVoteExtension` must set `ResponseVerifyVoteExtension.accept` to _true_ if the extension is an empty byte array and _false_ otherwise, then return. -* `FinalizeBlock` should coalesce the implementation of methods `BeginBlock`, `DeliverTx`, `EndBlock`, and `Commit`. - The logic extracted from `DeliverTx` should be wrappped by a loop that will execute as many times as - transactions exist in `RequestFinalizeBlock.tx`. +* `FinalizeBlock` is to coalesce the implementation of methods `BeginBlock`, `DeliverTx`, `EndBlock`, and `Commit`. + Legacy applications looking to reuse old code that implemented `DeliverTx` should wrap the legacy + `DeliverTx` logic in a loop that executes one transaction iteration per + transaction in `RequestFinalizeBlock.tx`. diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 1ed1055ca..051a1ddbb 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -306,7 +306,19 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a func (app *Application) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { // None of the transactions are modified by this application. - return abci.ResponsePrepareProposal{ModifiedTxStatus: abci.ResponsePrepareProposal_UNMODIFIED} + trs := make([]*abci.TxRecord, 0, len(req.Txs)) + var totalBytes int64 + for _, tx := range req.Txs { + totalBytes += int64(len(tx)) + if totalBytes > req.MaxTxBytes { + break + } + trs = append(trs, &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + }) + } + return abci.ResponsePrepareProposal{TxRecords: trs} } // ProcessProposal implements part of the Application interface. diff --git a/types/tx.go b/types/tx.go index 0c354a941..c879cf3da 100644 --- a/types/tx.go +++ b/types/tx.go @@ -205,7 +205,7 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { for _, cur := range append(unmodifiedCopy, addedCopy...) { size += int64(len(cur)) if size > maxSizeBytes { - return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes) + return fmt.Errorf("transaction data size exceeds maximum %d", maxSizeBytes) } } From cb8e6b1c1a4f3d86f307f38a0673893ab66788e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Apr 2022 14:25:00 +0000 Subject: [PATCH 11/20] build(deps): Bump github.com/vektra/mockery/v2 from 2.10.1 to 2.10.2 (#8246) Bumps [github.com/vektra/mockery/v2](https://github.com/vektra/mockery) from 2.10.1 to 2.10.2.
Release notes

Sourced from github.com/vektra/mockery/v2's releases.

v2.10.2

Changelog

  • 8384e25 Merge pull request #443 from OrlovEvgeny/fix-build-go-version
  • 408740d fix: golang build version
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/vektra/mockery/v2&package-manager=go_modules&previous-version=2.10.1&new-version=2.10.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 21afc3375..7951b645f 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/creachadair/atomicfile v0.2.4 github.com/golangci/golangci-lint v1.45.2 github.com/google/go-cmp v0.5.7 - github.com/vektra/mockery/v2 v2.10.1 + github.com/vektra/mockery/v2 v2.10.2 gotest.tools v2.2.0+incompatible ) diff --git a/go.sum b/go.sum index 19aeb8f1f..60b4842b6 100644 --- a/go.sum +++ b/go.sum @@ -1035,8 +1035,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vektra/mockery/v2 v2.10.1 h1:EOsWLFVlkUJlNurdO/w1NBFbFE1vbemJJtaG3Bo6H/M= -github.com/vektra/mockery/v2 v2.10.1/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4= +github.com/vektra/mockery/v2 v2.10.2 h1:ISAFkB3rQS6Y3aDZzAKtDwgeyDknwNa1aBE3Zgx0h+I= +github.com/vektra/mockery/v2 v2.10.2/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= From 97f7021712cbc0db8891a1f17c1c7406636e7c1a Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Mon, 4 Apr 2022 12:31:15 -0400 Subject: [PATCH 12/20] statesync: merge channel processing (#8240) --- internal/blocksync/reactor.go | 1 + internal/consensus/reactor.go | 4 +++ internal/evidence/reactor.go | 1 + internal/mempool/reactor.go | 1 + internal/p2p/channel.go | 3 ++ internal/p2p/conn/connection.go | 4 +++ internal/p2p/pex/reactor.go | 1 + internal/p2p/router.go | 1 + internal/statesync/reactor.go | 53 ++++++++++++++++++++++-------- internal/statesync/reactor_test.go | 41 ++++++++++++++--------- 10 files changed, 81 insertions(+), 29 deletions(-) diff --git a/internal/blocksync/reactor.go b/internal/blocksync/reactor.go index b9c4e498c..34ed1f0fc 100644 --- a/internal/blocksync/reactor.go +++ b/internal/blocksync/reactor.go @@ -45,6 +45,7 @@ func GetChannelDescriptor() *p2p.ChannelDescriptor { SendQueueCapacity: 1000, RecvBufferCapacity: 1024, RecvMessageCapacity: MaxMsgSize, + Name: "blockSync", } } diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index c8d296ff9..b11775679 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -38,6 +38,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 64, RecvMessageCapacity: maxMsgSize, RecvBufferCapacity: 128, + Name: "state", }, DataChannel: { // TODO: Consider a split between gossiping current block and catchup @@ -49,6 +50,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 64, RecvBufferCapacity: 512, RecvMessageCapacity: maxMsgSize, + Name: "data", }, VoteChannel: { ID: VoteChannel, @@ -57,6 +59,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 64, RecvBufferCapacity: 128, RecvMessageCapacity: maxMsgSize, + Name: "vote", }, VoteSetBitsChannel: { ID: VoteSetBitsChannel, @@ -65,6 +68,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 8, RecvBufferCapacity: 128, RecvMessageCapacity: maxMsgSize, + Name: "voteSet", }, } } diff --git a/internal/evidence/reactor.go b/internal/evidence/reactor.go index 1011f732f..c52e7e32b 100644 --- a/internal/evidence/reactor.go +++ b/internal/evidence/reactor.go @@ -38,6 +38,7 @@ func GetChannelDescriptor() *p2p.ChannelDescriptor { Priority: 6, RecvMessageCapacity: maxMsgSize, RecvBufferCapacity: 32, + Name: "evidence", } } diff --git a/internal/mempool/reactor.go b/internal/mempool/reactor.go index 8f98d97f1..816589c9b 100644 --- a/internal/mempool/reactor.go +++ b/internal/mempool/reactor.go @@ -106,6 +106,7 @@ func getChannelDescriptor(cfg *config.MempoolConfig) *p2p.ChannelDescriptor { Priority: 5, RecvMessageCapacity: batchMsg.Size(), RecvBufferCapacity: 128, + Name: "mempool", } } diff --git a/internal/p2p/channel.go b/internal/p2p/channel.go index d7dad4d3b..8e6774612 100644 --- a/internal/p2p/channel.go +++ b/internal/p2p/channel.go @@ -60,6 +60,7 @@ type Channel struct { errCh chan<- PeerError // peer error reporting messageType proto.Message // the channel's message type, used for unmarshaling + name string } // NewChannel creates a new channel. It is primarily for internal and test @@ -102,6 +103,8 @@ func (ch *Channel) SendError(ctx context.Context, pe PeerError) error { } } +func (ch *Channel) String() string { return fmt.Sprintf("p2p.Channel<%d:%s>", ch.ID, ch.name) } + // Receive returns a new unbuffered iterator to receive messages from ch. // The iterator runs until ctx ends. func (ch *Channel) Receive(ctx context.Context) *ChannelIterator { diff --git a/internal/p2p/conn/connection.go b/internal/p2p/conn/connection.go index 4cbca7f19..c8fc21188 100644 --- a/internal/p2p/conn/connection.go +++ b/internal/p2p/conn/connection.go @@ -616,6 +616,10 @@ type ChannelDescriptor struct { // RecvBufferCapacity defines the max buffer size of inbound messages for a // given p2p Channel queue. RecvBufferCapacity int + + // Human readable name of the channel, used in logging and + // diagnostics. + Name string } func (chDesc ChannelDescriptor) FillDefaults() (filled ChannelDescriptor) { diff --git a/internal/p2p/pex/reactor.go b/internal/p2p/pex/reactor.go index 2beaeaa17..178524af2 100644 --- a/internal/p2p/pex/reactor.go +++ b/internal/p2p/pex/reactor.go @@ -63,6 +63,7 @@ func ChannelDescriptor() *conn.ChannelDescriptor { SendQueueCapacity: 10, RecvMessageCapacity: maxMsgSize, RecvBufferCapacity: 128, + Name: "pex", } } diff --git a/internal/p2p/router.go b/internal/p2p/router.go index f9b3d1ad8..40c24d56b 100644 --- a/internal/p2p/router.go +++ b/internal/p2p/router.go @@ -281,6 +281,7 @@ func (r *Router) OpenChannel(ctx context.Context, chDesc *ChannelDescriptor) (*C outCh := make(chan Envelope, chDesc.RecvBufferCapacity) errCh := make(chan PeerError, chDesc.RecvBufferCapacity) channel := NewChannel(id, messageType, queue.dequeue(), outCh, errCh) + channel.name = chDesc.Name var wrapper Wrapper if w, ok := messageType.(Wrapper); ok { diff --git a/internal/statesync/reactor.go b/internal/statesync/reactor.go index 51f626027..dba520a1c 100644 --- a/internal/statesync/reactor.go +++ b/internal/statesync/reactor.go @@ -16,6 +16,7 @@ import ( "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/p2p" + "github.com/tendermint/tendermint/internal/p2p/conn" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/store" "github.com/tendermint/tendermint/libs/log" @@ -75,13 +76,13 @@ const ( func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { return map[p2p.ChannelID]*p2p.ChannelDescriptor{ SnapshotChannel: { - ID: SnapshotChannel, MessageType: new(ssproto.Message), Priority: 6, SendQueueCapacity: 10, RecvMessageCapacity: snapshotMsgSize, RecvBufferCapacity: 128, + Name: "snapshot", }, ChunkChannel: { ID: ChunkChannel, @@ -90,6 +91,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 4, RecvMessageCapacity: chunkMsgSize, RecvBufferCapacity: 128, + Name: "chunk", }, LightBlockChannel: { ID: LightBlockChannel, @@ -98,6 +100,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 10, RecvMessageCapacity: lightBlockMsgSize, RecvBufferCapacity: 128, + Name: "light-block", }, ParamsChannel: { ID: ParamsChannel, @@ -106,6 +109,7 @@ func getChannelDescriptors() map[p2p.ChannelID]*p2p.ChannelDescriptor { SendQueueCapacity: 10, RecvMessageCapacity: paramMsgSize, RecvBufferCapacity: 128, + Name: "params", }, } @@ -233,10 +237,7 @@ func NewReactor( // The caller must be sure to execute OnStop to ensure the outbound p2p Channels are // closed. No error is returned. func (r *Reactor) OnStart(ctx context.Context) error { - go r.processCh(ctx, r.snapshotCh, "snapshot") - go r.processCh(ctx, r.chunkCh, "chunk") - go r.processCh(ctx, r.blockCh, "light block") - go r.processCh(ctx, r.paramsCh, "consensus params") + go r.processChannels(ctx, r.snapshotCh, r.chunkCh, r.blockCh, r.paramsCh) go r.processPeerUpdates(ctx) return nil @@ -291,6 +292,7 @@ func (r *Reactor) Sync(ctx context.Context) (sm.State, error) { r.metrics, ) r.mtx.Unlock() + defer func() { r.mtx.Lock() // reset syncing objects at the close of Sync @@ -780,6 +782,8 @@ func (r *Reactor) handleParamsMessage(ctx context.Context, envelope *p2p.Envelop if sp, ok := r.stateProvider.(*stateProviderP2P); ok { select { case sp.paramsRecvCh <- cp: + case <-ctx.Done(): + return ctx.Err() case <-time.After(time.Second): return errors.New("failed to send consensus params, stateprovider not ready for response") } @@ -797,7 +801,7 @@ func (r *Reactor) handleParamsMessage(ctx context.Context, envelope *p2p.Envelop // handleMessage handles an Envelope sent from a peer on a specific p2p Channel. // It will handle errors and any possible panics gracefully. A caller can handle // any error returned by sending a PeerError on the respective channel. -func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelope *p2p.Envelope) (err error) { +func (r *Reactor) handleMessage(ctx context.Context, envelope *p2p.Envelope) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("panic in processing message: %v", e) @@ -811,7 +815,7 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop r.logger.Debug("received message", "message", reflect.TypeOf(envelope.Message), "peer", envelope.From) - switch chID { + switch envelope.ChannelID { case SnapshotChannel: err = r.handleSnapshotMessage(ctx, envelope) case ChunkChannel: @@ -821,7 +825,7 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop case ParamsChannel: err = r.handleParamsMessage(ctx, envelope) default: - err = fmt.Errorf("unknown channel ID (%d) for envelope (%v)", chID, envelope) + err = fmt.Errorf("unknown channel ID (%d) for envelope (%v)", envelope.ChannelID, envelope) } return err @@ -831,15 +835,35 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop // encountered during message execution will result in a PeerError being sent on // the respective channel. When the reactor is stopped, we will catch the signal // and close the p2p Channel gracefully. -func (r *Reactor) processCh(ctx context.Context, ch *p2p.Channel, chName string) { - iter := ch.Receive(ctx) +func (r *Reactor) processChannels(ctx context.Context, chs ...*p2p.Channel) { + // make sure that the iterator gets cleaned up in case of error + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + chanTable := make(map[conn.ChannelID]*p2p.Channel, len(chs)) + for idx := range chs { + ch := chs[idx] + chanTable[ch.ID] = ch + } + + iter := p2p.MergedChannelIterator(ctx, chs...) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, ch.ID, envelope); err != nil { + if err := r.handleMessage(ctx, envelope); err != nil { + ch, ok := chanTable[envelope.ChannelID] + if !ok { + r.logger.Error("received impossible message", + "envelope_from", envelope.From, + "envelope_ch", envelope.ChannelID, + "num_chs", len(chanTable), + "err", err, + ) + return + } r.logger.Error("failed to process message", "err", err, - "channel", chName, - "ch_id", ch.ID, + "channel", ch.String(), + "ch_id", envelope.ChannelID, "envelope", envelope) if serr := ch.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, @@ -875,14 +899,15 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda r.mtx.Lock() defer r.mtx.Unlock() + if r.syncer == nil { return } switch peerUpdate.Status { case p2p.PeerStatusUp: - newProvider := NewBlockProvider(peerUpdate.NodeID, r.chainID, r.dispatcher) + r.providers[peerUpdate.NodeID] = newProvider err := r.syncer.AddPeer(ctx, peerUpdate.NodeID) if err != nil { diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index c1ac1a048..709fe9a2c 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -257,8 +257,9 @@ func TestReactor_ChunkRequest_InvalidRequest(t *testing.T) { rts := setup(ctx, t, nil, nil, 2) rts.chunkInCh <- p2p.Envelope{ - From: types.NodeID("aa"), - Message: &ssproto.SnapshotsRequest{}, + From: types.NodeID("aa"), + ChannelID: ChunkChannel, + Message: &ssproto.SnapshotsRequest{}, } response := <-rts.chunkPeerErrCh @@ -315,8 +316,9 @@ func TestReactor_ChunkRequest(t *testing.T) { rts := setup(ctx, t, conn, nil, 2) rts.chunkInCh <- p2p.Envelope{ - From: types.NodeID("aa"), - Message: tc.request, + From: types.NodeID("aa"), + ChannelID: ChunkChannel, + Message: tc.request, } response := <-rts.chunkOutCh @@ -335,8 +337,9 @@ func TestReactor_SnapshotsRequest_InvalidRequest(t *testing.T) { rts := setup(ctx, t, nil, nil, 2) rts.snapshotInCh <- p2p.Envelope{ - From: types.NodeID("aa"), - Message: &ssproto.ChunkRequest{}, + From: types.NodeID("aa"), + ChannelID: SnapshotChannel, + Message: &ssproto.ChunkRequest{}, } response := <-rts.snapshotPeerErrCh @@ -400,8 +403,9 @@ func TestReactor_SnapshotsRequest(t *testing.T) { rts := setup(ctx, t, conn, nil, 100) rts.snapshotInCh <- p2p.Envelope{ - From: types.NodeID("aa"), - Message: &ssproto.SnapshotsRequest{}, + From: types.NodeID("aa"), + ChannelID: SnapshotChannel, + Message: &ssproto.SnapshotsRequest{}, } if len(tc.expectResponses) > 0 { @@ -457,7 +461,8 @@ func TestReactor_LightBlockResponse(t *testing.T) { rts.stateStore.On("LoadValidators", height).Return(vals, nil) rts.blockInCh <- p2p.Envelope{ - From: types.NodeID("aa"), + From: types.NodeID("aa"), + ChannelID: LightBlockChannel, Message: &ssproto.LightBlockRequest{ Height: 10, }, @@ -733,7 +738,8 @@ func handleLightBlockRequests( require.NoError(t, err) select { case sending <- p2p.Envelope{ - From: envelope.To, + From: envelope.To, + ChannelID: LightBlockChannel, Message: &ssproto.LightBlockResponse{ LightBlock: lb, }, @@ -750,7 +756,8 @@ func handleLightBlockRequests( require.NoError(t, err) select { case sending <- p2p.Envelope{ - From: envelope.To, + From: envelope.To, + ChannelID: LightBlockChannel, Message: &ssproto.LightBlockResponse{ LightBlock: differntLB, }, @@ -761,7 +768,8 @@ func handleLightBlockRequests( case 1: // send nil block i.e. pretend we don't have it select { case sending <- p2p.Envelope{ - From: envelope.To, + From: envelope.To, + ChannelID: LightBlockChannel, Message: &ssproto.LightBlockResponse{ LightBlock: nil, }, @@ -802,7 +810,8 @@ func handleConsensusParamsRequest( } select { case sending <- p2p.Envelope{ - From: envelope.To, + From: envelope.To, + ChannelID: ParamsChannel, Message: &ssproto.ParamsResponse{ Height: msg.Height, ConsensusParams: paramsProto, @@ -913,7 +922,8 @@ func handleSnapshotRequests( require.True(t, ok) for _, snapshot := range snapshots { sendingCh <- p2p.Envelope{ - From: envelope.To, + From: envelope.To, + ChannelID: SnapshotChannel, Message: &ssproto.SnapshotsResponse{ Height: snapshot.Height, Format: snapshot.Format, @@ -946,7 +956,8 @@ func handleChunkRequests( msg, ok := envelope.Message.(*ssproto.ChunkRequest) require.True(t, ok) sendingCh <- p2p.Envelope{ - From: envelope.To, + From: envelope.To, + ChannelID: ChunkChannel, Message: &ssproto.ChunkResponse{ Height: msg.Height, Format: msg.Format, From 9d1e8eaad46e78d6c9d1caf912ab181c11a780c6 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Tue, 5 Apr 2022 09:26:53 -0400 Subject: [PATCH 13/20] node: remove channel and peer update initialization from construction (#8238) --- internal/blocksync/reactor.go | 163 +++++++++-------- internal/blocksync/reactor_test.go | 6 +- internal/consensus/byzantine_test.go | 6 +- internal/consensus/invalid_test.go | 5 +- internal/consensus/reactor.go | 251 ++++++++++++++------------- internal/consensus/reactor_test.go | 5 +- internal/evidence/reactor.go | 60 +++---- internal/evidence/reactor_test.go | 11 +- internal/mempool/reactor.go | 80 ++++----- internal/mempool/reactor_test.go | 11 +- internal/p2p/p2ptest/network.go | 1 - internal/p2p/peermanager.go | 5 + internal/p2p/pex/reactor.go | 56 +++--- internal/p2p/pex/reactor_test.go | 31 ++-- internal/p2p/router.go | 22 ++- internal/p2p/router_init_test.go | 14 +- internal/p2p/router_test.go | 10 -- internal/statesync/reactor.go | 242 +++++++++++++------------- internal/statesync/reactor_test.go | 28 +-- internal/statesync/syncer.go | 26 --- node/node.go | 44 ++--- node/node_test.go | 4 +- node/public.go | 2 +- node/seed.go | 13 +- node/setup.go | 58 +++---- 25 files changed, 545 insertions(+), 609 deletions(-) diff --git a/internal/blocksync/reactor.go b/internal/blocksync/reactor.go index 34ed1f0fc..6533fa046 100644 --- a/internal/blocksync/reactor.go +++ b/internal/blocksync/reactor.go @@ -11,6 +11,7 @@ import ( "github.com/tendermint/tendermint/internal/consensus" "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/p2p" + "github.com/tendermint/tendermint/internal/p2p/conn" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/store" "github.com/tendermint/tendermint/libs/log" @@ -80,8 +81,8 @@ type Reactor struct { consReactor consensusReactor blockSync *atomicBool - blockSyncCh *p2p.Channel - peerUpdates *p2p.PeerUpdates + chCreator p2p.ChannelCreator + peerEvents p2p.PeerEventSubscriber requestsCh <-chan BlockRequest errorsCh <-chan peerError @@ -94,23 +95,17 @@ type Reactor struct { // NewReactor returns new reactor instance. func NewReactor( - ctx context.Context, logger log.Logger, stateStore sm.Store, blockExec *sm.BlockExecutor, store *store.BlockStore, consReactor consensusReactor, channelCreator p2p.ChannelCreator, - peerUpdates *p2p.PeerUpdates, + peerEvents p2p.PeerEventSubscriber, blockSync bool, metrics *consensus.Metrics, eventBus *eventbus.EventBus, -) (*Reactor, error) { - blockSyncCh, err := channelCreator(ctx, GetChannelDescriptor()) - if err != nil { - return nil, err - } - +) *Reactor { r := &Reactor{ logger: logger, stateStore: stateStore, @@ -118,14 +113,14 @@ func NewReactor( store: store, consReactor: consReactor, blockSync: newAtomicBool(blockSync), - blockSyncCh: blockSyncCh, - peerUpdates: peerUpdates, + chCreator: channelCreator, + peerEvents: peerEvents, metrics: metrics, eventBus: eventBus, } r.BaseService = *service.NewBaseService(logger, "BlockSync", r) - return r, nil + return r } // OnStart starts separate go routines for each p2p Channel and listens for @@ -136,6 +131,12 @@ func NewReactor( // If blockSync is enabled, we also start the pool and the pool processing // goroutine. If the pool fails to start, an error is returned. func (r *Reactor) OnStart(ctx context.Context) error { + blockSyncCh, err := r.chCreator(ctx, GetChannelDescriptor()) + if err != nil { + return err + } + r.chCreator = func(context.Context, *conn.ChannelDescriptor) (*p2p.Channel, error) { return blockSyncCh, nil } + state, err := r.stateStore.Load() if err != nil { return err @@ -161,13 +162,13 @@ func (r *Reactor) OnStart(ctx context.Context) error { if err := r.pool.Start(ctx); err != nil { return err } - go r.requestRoutine(ctx) + go r.requestRoutine(ctx, blockSyncCh) - go r.poolRoutine(ctx, false) + go r.poolRoutine(ctx, false, blockSyncCh) } - go r.processBlockSyncCh(ctx) - go r.processPeerUpdates(ctx) + go r.processBlockSyncCh(ctx, blockSyncCh) + go r.processPeerUpdates(ctx, r.peerEvents(ctx), blockSyncCh) return nil } @@ -182,7 +183,7 @@ func (r *Reactor) OnStop() { // respondToPeer loads a block and sends it to the requesting peer, if we have it. // Otherwise, we'll respond saying we do not have it. -func (r *Reactor) respondToPeer(ctx context.Context, msg *bcproto.BlockRequest, peerID types.NodeID) error { +func (r *Reactor) respondToPeer(ctx context.Context, msg *bcproto.BlockRequest, peerID types.NodeID, blockSyncCh *p2p.Channel) error { block := r.store.LoadBlock(msg.Height) if block != nil { blockProto, err := block.ToProto() @@ -191,7 +192,7 @@ func (r *Reactor) respondToPeer(ctx context.Context, msg *bcproto.BlockRequest, return err } - return r.blockSyncCh.Send(ctx, p2p.Envelope{ + return blockSyncCh.Send(ctx, p2p.Envelope{ To: peerID, Message: &bcproto.BlockResponse{Block: blockProto}, }) @@ -199,55 +200,16 @@ func (r *Reactor) respondToPeer(ctx context.Context, msg *bcproto.BlockRequest, r.logger.Info("peer requesting a block we do not have", "peer", peerID, "height", msg.Height) - return r.blockSyncCh.Send(ctx, p2p.Envelope{ + return blockSyncCh.Send(ctx, p2p.Envelope{ To: peerID, Message: &bcproto.NoBlockResponse{Height: msg.Height}, }) } -// handleBlockSyncMessage handles envelopes sent from peers on the -// BlockSyncChannel. It returns an error only if the Envelope.Message is unknown -// for this channel. This should never be called outside of handleMessage. -func (r *Reactor) handleBlockSyncMessage(ctx context.Context, envelope *p2p.Envelope) error { - logger := r.logger.With("peer", envelope.From) - - switch msg := envelope.Message.(type) { - case *bcproto.BlockRequest: - return r.respondToPeer(ctx, msg, envelope.From) - case *bcproto.BlockResponse: - block, err := types.BlockFromProto(msg.Block) - if err != nil { - logger.Error("failed to convert block from proto", "err", err) - return err - } - - r.pool.AddBlock(envelope.From, block, block.Size()) - - case *bcproto.StatusRequest: - return r.blockSyncCh.Send(ctx, p2p.Envelope{ - To: envelope.From, - Message: &bcproto.StatusResponse{ - Height: r.store.Height(), - Base: r.store.Base(), - }, - }) - case *bcproto.StatusResponse: - r.pool.SetPeerRange(envelope.From, msg.Base, msg.Height) - - case *bcproto.NoBlockResponse: - logger.Debug("peer does not have the requested block", "height", msg.Height) - - default: - return fmt.Errorf("received unknown message: %T", msg) - } - - return nil -} - // handleMessage handles an Envelope sent from a peer on a specific p2p Channel. // It will handle errors and any possible panics gracefully. A caller can handle // any error returned by sending a PeerError on the respective channel. -func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelope *p2p.Envelope) (err error) { +func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelope *p2p.Envelope, blockSyncCh *p2p.Channel) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("panic in processing message: %v", e) @@ -263,7 +225,39 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop switch chID { case BlockSyncChannel: - err = r.handleBlockSyncMessage(ctx, envelope) + switch msg := envelope.Message.(type) { + case *bcproto.BlockRequest: + return r.respondToPeer(ctx, msg, envelope.From, blockSyncCh) + case *bcproto.BlockResponse: + block, err := types.BlockFromProto(msg.Block) + if err != nil { + r.logger.Error("failed to convert block from proto", + "peer", envelope.From, + "err", err) + return err + } + + r.pool.AddBlock(envelope.From, block, block.Size()) + + case *bcproto.StatusRequest: + return blockSyncCh.Send(ctx, p2p.Envelope{ + To: envelope.From, + Message: &bcproto.StatusResponse{ + Height: r.store.Height(), + Base: r.store.Base(), + }, + }) + case *bcproto.StatusResponse: + r.pool.SetPeerRange(envelope.From, msg.Base, msg.Height) + + case *bcproto.NoBlockResponse: + r.logger.Debug("peer does not have the requested block", + "peer", envelope.From, + "height", msg.Height) + + default: + return fmt.Errorf("received unknown message: %T", msg) + } default: err = fmt.Errorf("unknown channel ID (%d) for envelope (%v)", chID, envelope) @@ -277,17 +271,17 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop // message execution will result in a PeerError being sent on the BlockSyncChannel. // When the reactor is stopped, we will catch the signal and close the p2p Channel // gracefully. -func (r *Reactor) processBlockSyncCh(ctx context.Context) { - iter := r.blockSyncCh.Receive(ctx) +func (r *Reactor) processBlockSyncCh(ctx context.Context, blockSyncCh *p2p.Channel) { + iter := blockSyncCh.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.blockSyncCh.ID, envelope); err != nil { + if err := r.handleMessage(ctx, blockSyncCh.ID, envelope, blockSyncCh); err != nil { if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { return } - r.logger.Error("failed to process message", "ch_id", r.blockSyncCh.ID, "envelope", envelope, "err", err) - if serr := r.blockSyncCh.SendError(ctx, p2p.PeerError{ + r.logger.Error("failed to process message", "ch_id", blockSyncCh.ID, "envelope", envelope, "err", err) + if serr := blockSyncCh.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -298,7 +292,7 @@ func (r *Reactor) processBlockSyncCh(ctx context.Context) { } // processPeerUpdate processes a PeerUpdate. -func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate) { +func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate, blockSyncCh *p2p.Channel) { r.logger.Debug("received peer update", "peer", peerUpdate.NodeID, "status", peerUpdate.Status) // XXX: Pool#RedoRequest can sometimes give us an empty peer. @@ -309,7 +303,7 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda switch peerUpdate.Status { case p2p.PeerStatusUp: // send a status update the newly added peer - if err := r.blockSyncCh.Send(ctx, p2p.Envelope{ + if err := blockSyncCh.Send(ctx, p2p.Envelope{ To: peerUpdate.NodeID, Message: &bcproto.StatusResponse{ Base: r.store.Base(), @@ -317,7 +311,7 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda }, }); err != nil { r.pool.RemovePeer(peerUpdate.NodeID) - if err := r.blockSyncCh.SendError(ctx, p2p.PeerError{ + if err := blockSyncCh.SendError(ctx, p2p.PeerError{ NodeID: peerUpdate.NodeID, Err: err, }); err != nil { @@ -333,13 +327,13 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda // processPeerUpdates initiates a blocking process where we listen for and handle // PeerUpdate messages. When the reactor is stopped, we will catch the signal and // close the p2p PeerUpdatesCh gracefully. -func (r *Reactor) processPeerUpdates(ctx context.Context) { +func (r *Reactor) processPeerUpdates(ctx context.Context, peerUpdates *p2p.PeerUpdates, blockSyncCh *p2p.Channel) { for { select { case <-ctx.Done(): return - case peerUpdate := <-r.peerUpdates.Updates(): - r.processPeerUpdate(ctx, peerUpdate) + case peerUpdate := <-peerUpdates.Updates(): + r.processPeerUpdate(ctx, peerUpdate, blockSyncCh) } } } @@ -357,13 +351,18 @@ func (r *Reactor) SwitchToBlockSync(ctx context.Context, state sm.State) error { r.syncStartTime = time.Now() - go r.requestRoutine(ctx) - go r.poolRoutine(ctx, true) + bsCh, err := r.chCreator(ctx, GetChannelDescriptor()) + if err != nil { + return err + } + + go r.requestRoutine(ctx, bsCh) + go r.poolRoutine(ctx, true, bsCh) return nil } -func (r *Reactor) requestRoutine(ctx context.Context) { +func (r *Reactor) requestRoutine(ctx context.Context, blockSyncCh *p2p.Channel) { statusUpdateTicker := time.NewTicker(statusUpdateIntervalSeconds * time.Second) defer statusUpdateTicker.Stop() @@ -372,11 +371,11 @@ func (r *Reactor) requestRoutine(ctx context.Context) { case <-ctx.Done(): return case request := <-r.requestsCh: - if err := r.blockSyncCh.Send(ctx, p2p.Envelope{ + if err := blockSyncCh.Send(ctx, p2p.Envelope{ To: request.PeerID, Message: &bcproto.BlockRequest{Height: request.Height}, }); err != nil { - if err := r.blockSyncCh.SendError(ctx, p2p.PeerError{ + if err := blockSyncCh.SendError(ctx, p2p.PeerError{ NodeID: request.PeerID, Err: err, }); err != nil { @@ -384,14 +383,14 @@ func (r *Reactor) requestRoutine(ctx context.Context) { } } case pErr := <-r.errorsCh: - if err := r.blockSyncCh.SendError(ctx, p2p.PeerError{ + if err := blockSyncCh.SendError(ctx, p2p.PeerError{ NodeID: pErr.peerID, Err: pErr.err, }); err != nil { return } case <-statusUpdateTicker.C: - if err := r.blockSyncCh.Send(ctx, p2p.Envelope{ + if err := blockSyncCh.Send(ctx, p2p.Envelope{ Broadcast: true, Message: &bcproto.StatusRequest{}, }); err != nil { @@ -405,7 +404,7 @@ func (r *Reactor) requestRoutine(ctx context.Context) { // do. // // NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down! -func (r *Reactor) poolRoutine(ctx context.Context, stateSynced bool) { +func (r *Reactor) poolRoutine(ctx context.Context, stateSynced bool, blockSyncCh *p2p.Channel) { var ( trySyncTicker = time.NewTicker(trySyncIntervalMS * time.Millisecond) switchToConsensusTicker = time.NewTicker(switchToConsensusIntervalSeconds * time.Second) @@ -523,7 +522,7 @@ func (r *Reactor) poolRoutine(ctx context.Context, stateSynced bool) { // NOTE: We've already removed the peer's request, but we still need // to clean up the rest. peerID := r.pool.RedoRequest(first.Height) - if serr := r.blockSyncCh.SendError(ctx, p2p.PeerError{ + if serr := blockSyncCh.SendError(ctx, p2p.PeerError{ NodeID: peerID, Err: err, }); serr != nil { @@ -532,7 +531,7 @@ func (r *Reactor) poolRoutine(ctx context.Context, stateSynced bool) { peerID2 := r.pool.RedoRequest(second.Height) if peerID2 != peerID { - if serr := r.blockSyncCh.SendError(ctx, p2p.PeerError{ + if serr := blockSyncCh.SendError(ctx, p2p.PeerError{ NodeID: peerID2, Err: err, }); serr != nil { diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index e35d45a74..065d75301 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -190,20 +190,18 @@ func (rts *reactorTestSuite) addNode( chCreator := func(ctx context.Context, chdesc *p2p.ChannelDescriptor) (*p2p.Channel, error) { return rts.blockSyncChannels[nodeID], nil } - rts.reactors[nodeID], err = NewReactor( - ctx, + rts.reactors[nodeID] = NewReactor( rts.logger.With("nodeID", nodeID), stateStore, blockExec, blockStore, nil, chCreator, - rts.peerUpdates[nodeID], + func(ctx context.Context) *p2p.PeerUpdates { return rts.peerUpdates[nodeID] }, rts.blockSync, consensus.NopMetrics(), nil, // eventbus, can be nil ) - require.NoError(t, err) require.NoError(t, rts.reactors[nodeID].Start(ctx)) require.True(t, rts.reactors[nodeID].IsRunning()) diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index f631452bd..cfcf8b04f 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -141,8 +141,10 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { // send two votes to all peers (1st to one half, 2nd to another half) i := 0 for _, ps := range bzReactor.peers { + voteCh := rts.voteChannels[bzNodeID] if i < len(bzReactor.peers)/2 { - require.NoError(t, bzReactor.voteCh.Send(ctx, + + require.NoError(t, voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.Vote{ @@ -150,7 +152,7 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { }, })) } else { - require.NoError(t, bzReactor.voteCh.Send(ctx, + require.NoError(t, voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.Vote{ diff --git a/internal/consensus/invalid_test.go b/internal/consensus/invalid_test.go index f38598af9..93c5cea1b 100644 --- a/internal/consensus/invalid_test.go +++ b/internal/consensus/invalid_test.go @@ -57,7 +57,7 @@ func TestReactorInvalidPrecommit(t *testing.T) { privVal := byzState.privValidator byzState.doPrevote = func(ctx context.Context, height int64, round int32) { defer close(signal) - invalidDoPrevoteFunc(ctx, t, height, round, byzState, byzReactor, privVal) + invalidDoPrevoteFunc(ctx, t, height, round, byzState, byzReactor, rts.voteChannels[node.NodeID], privVal) } byzState.mtx.Unlock() @@ -107,6 +107,7 @@ func invalidDoPrevoteFunc( round int32, cs *State, r *Reactor, + voteCh *p2p.Channel, pv types.PrivValidator, ) { // routine to: @@ -155,7 +156,7 @@ func invalidDoPrevoteFunc( count := 0 for _, peerID := range ids { count++ - err := r.voteCh.Send(ctx, p2p.Envelope{ + err := voteCh.Send(ctx, p2p.Envelope{ To: peerID, Message: &tmcons.Vote{ Vote: precommit.ToProto(), diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index b11775679..4bc109515 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -126,11 +126,8 @@ type Reactor struct { rs *cstypes.RoundState readySignal chan struct{} // closed when the node is ready to start consensus - stateCh *p2p.Channel - dataCh *p2p.Channel - voteCh *p2p.Channel - voteSetBitsCh *p2p.Channel - peerUpdates *p2p.PeerUpdates + peerEvents p2p.PeerEventSubscriber + chCreator p2p.ChannelCreator } // NewReactor returns a reference to a new consensus reactor, which implements @@ -138,49 +135,25 @@ type Reactor struct { // to relevant p2p Channels and a channel to listen for peer updates on. The // reactor will close all p2p Channels when stopping. func NewReactor( - ctx context.Context, logger log.Logger, cs *State, channelCreator p2p.ChannelCreator, - peerUpdates *p2p.PeerUpdates, + peerEvents p2p.PeerEventSubscriber, eventBus *eventbus.EventBus, waitSync bool, metrics *Metrics, -) (*Reactor, error) { - chans := getChannelDescriptors() - stateCh, err := channelCreator(ctx, chans[StateChannel]) - if err != nil { - return nil, err - } - - dataCh, err := channelCreator(ctx, chans[DataChannel]) - if err != nil { - return nil, err - } - - voteCh, err := channelCreator(ctx, chans[VoteChannel]) - if err != nil { - return nil, err - } - - voteSetBitsCh, err := channelCreator(ctx, chans[VoteSetBitsChannel]) - if err != nil { - return nil, err - } +) *Reactor { r := &Reactor{ - logger: logger, - state: cs, - waitSync: waitSync, - rs: cs.GetRoundState(), - peers: make(map[types.NodeID]*PeerState), - eventBus: eventBus, - Metrics: metrics, - stateCh: stateCh, - dataCh: dataCh, - voteCh: voteCh, - voteSetBitsCh: voteSetBitsCh, - peerUpdates: peerUpdates, - readySignal: make(chan struct{}), + logger: logger, + state: cs, + waitSync: waitSync, + rs: cs.GetRoundState(), + peers: make(map[types.NodeID]*PeerState), + eventBus: eventBus, + Metrics: metrics, + peerEvents: peerEvents, + chCreator: channelCreator, + readySignal: make(chan struct{}), } r.BaseService = *service.NewBaseService(logger, "Consensus", r) @@ -188,7 +161,14 @@ func NewReactor( close(r.readySignal) } - return r, nil + return r +} + +type channelBundle struct { + state *p2p.Channel + data *p2p.Channel + vote *p2p.Channel + votSet *p2p.Channel } // OnStart starts separate go routines for each p2p Channel and listens for @@ -198,13 +178,39 @@ func NewReactor( func (r *Reactor) OnStart(ctx context.Context) error { r.logger.Debug("consensus wait sync", "wait_sync", r.WaitSync()) + peerUpdates := r.peerEvents(ctx) + + var chBundle channelBundle + var err error + + chans := getChannelDescriptors() + chBundle.state, err = r.chCreator(ctx, chans[StateChannel]) + if err != nil { + return err + } + + chBundle.data, err = r.chCreator(ctx, chans[DataChannel]) + if err != nil { + return err + } + + chBundle.vote, err = r.chCreator(ctx, chans[VoteChannel]) + if err != nil { + return err + } + + chBundle.votSet, err = r.chCreator(ctx, chans[VoteSetBitsChannel]) + if err != nil { + return err + } + // start routine that computes peer statistics for evaluating peer quality // // TODO: Evaluate if we need this to be synchronized via WaitGroup as to not // leak the goroutine when stopping the reactor. - go r.peerStatsRoutine(ctx) + go r.peerStatsRoutine(ctx, peerUpdates) - r.subscribeToBroadcastEvents() + r.subscribeToBroadcastEvents(chBundle.state) go r.updateRoundStateRoutine() if !r.WaitSync() { @@ -213,11 +219,11 @@ func (r *Reactor) OnStart(ctx context.Context) error { } } - go r.processStateCh(ctx) - go r.processDataCh(ctx) - go r.processVoteCh(ctx) - go r.processVoteSetBitsCh(ctx) - go r.processPeerUpdates(ctx) + go r.processStateCh(ctx, chBundle) + go r.processDataCh(ctx, chBundle) + go r.processVoteCh(ctx, chBundle) + go r.processVoteSetBitsCh(ctx, chBundle) + go r.processPeerUpdates(ctx, peerUpdates, chBundle) return nil } @@ -318,16 +324,16 @@ func (r *Reactor) GetPeerState(peerID types.NodeID) (*PeerState, bool) { return ps, ok } -func (r *Reactor) broadcastNewRoundStepMessage(ctx context.Context, rs *cstypes.RoundState) error { - return r.stateCh.Send(ctx, p2p.Envelope{ +func (r *Reactor) broadcastNewRoundStepMessage(ctx context.Context, rs *cstypes.RoundState, stateCh *p2p.Channel) error { + return stateCh.Send(ctx, p2p.Envelope{ Broadcast: true, Message: makeRoundStepMessage(rs), }) } -func (r *Reactor) broadcastNewValidBlockMessage(ctx context.Context, rs *cstypes.RoundState) error { +func (r *Reactor) broadcastNewValidBlockMessage(ctx context.Context, rs *cstypes.RoundState, stateCh *p2p.Channel) error { psHeader := rs.ProposalBlockParts.Header() - return r.stateCh.Send(ctx, p2p.Envelope{ + return stateCh.Send(ctx, p2p.Envelope{ Broadcast: true, Message: &tmcons.NewValidBlock{ Height: rs.Height, @@ -339,8 +345,8 @@ func (r *Reactor) broadcastNewValidBlockMessage(ctx context.Context, rs *cstypes }) } -func (r *Reactor) broadcastHasVoteMessage(ctx context.Context, vote *types.Vote) error { - return r.stateCh.Send(ctx, p2p.Envelope{ +func (r *Reactor) broadcastHasVoteMessage(ctx context.Context, vote *types.Vote, stateCh *p2p.Channel) error { + return stateCh.Send(ctx, p2p.Envelope{ Broadcast: true, Message: &tmcons.HasVote{ Height: vote.Height, @@ -354,14 +360,14 @@ func (r *Reactor) broadcastHasVoteMessage(ctx context.Context, vote *types.Vote) // subscribeToBroadcastEvents subscribes for new round steps and votes using the // internal pubsub defined in the consensus state to broadcast them to peers // upon receiving. -func (r *Reactor) subscribeToBroadcastEvents() { +func (r *Reactor) subscribeToBroadcastEvents(stateCh *p2p.Channel) { onStopCh := r.state.getOnStopCh() err := r.state.evsw.AddListenerForEvent( listenerIDConsensus, types.EventNewRoundStepValue, func(ctx context.Context, data tmevents.EventData) error { - if err := r.broadcastNewRoundStepMessage(ctx, data.(*cstypes.RoundState)); err != nil { + if err := r.broadcastNewRoundStepMessage(ctx, data.(*cstypes.RoundState), stateCh); err != nil { return err } select { @@ -382,7 +388,7 @@ func (r *Reactor) subscribeToBroadcastEvents() { listenerIDConsensus, types.EventValidBlockValue, func(ctx context.Context, data tmevents.EventData) error { - return r.broadcastNewValidBlockMessage(ctx, data.(*cstypes.RoundState)) + return r.broadcastNewValidBlockMessage(ctx, data.(*cstypes.RoundState), stateCh) }, ) if err != nil { @@ -393,7 +399,7 @@ func (r *Reactor) subscribeToBroadcastEvents() { listenerIDConsensus, types.EventVoteValue, func(ctx context.Context, data tmevents.EventData) error { - return r.broadcastHasVoteMessage(ctx, data.(*types.Vote)) + return r.broadcastHasVoteMessage(ctx, data.(*types.Vote), stateCh) }, ) if err != nil { @@ -411,8 +417,8 @@ func makeRoundStepMessage(rs *cstypes.RoundState) *tmcons.NewRoundStep { } } -func (r *Reactor) sendNewRoundStepMessage(ctx context.Context, peerID types.NodeID) error { - return r.stateCh.Send(ctx, p2p.Envelope{ +func (r *Reactor) sendNewRoundStepMessage(ctx context.Context, peerID types.NodeID, stateCh *p2p.Channel) error { + return stateCh.Send(ctx, p2p.Envelope{ To: peerID, Message: makeRoundStepMessage(r.getRoundState()), }) @@ -438,7 +444,7 @@ func (r *Reactor) getRoundState() *cstypes.RoundState { return r.rs } -func (r *Reactor) gossipDataForCatchup(ctx context.Context, rs *cstypes.RoundState, prs *cstypes.PeerRoundState, ps *PeerState) { +func (r *Reactor) gossipDataForCatchup(ctx context.Context, rs *cstypes.RoundState, prs *cstypes.PeerRoundState, ps *PeerState, dataCh *p2p.Channel) { logger := r.logger.With("height", prs.Height).With("peer", ps.peerID) if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok { @@ -487,7 +493,7 @@ func (r *Reactor) gossipDataForCatchup(ctx context.Context, rs *cstypes.RoundSta } logger.Debug("sending block part for catchup", "round", prs.Round, "index", index) - _ = r.dataCh.Send(ctx, p2p.Envelope{ + _ = dataCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.BlockPart{ Height: prs.Height, // not our height, so it does not matter. @@ -502,7 +508,7 @@ func (r *Reactor) gossipDataForCatchup(ctx context.Context, rs *cstypes.RoundSta time.Sleep(r.state.config.PeerGossipSleepDuration) } -func (r *Reactor) gossipDataRoutine(ctx context.Context, ps *PeerState) { +func (r *Reactor) gossipDataRoutine(ctx context.Context, ps *PeerState, dataCh *p2p.Channel) { logger := r.logger.With("peer", ps.peerID) timer := time.NewTimer(0) @@ -534,7 +540,7 @@ OUTER_LOOP: } logger.Debug("sending block part", "height", prs.Height, "round", prs.Round) - if err := r.dataCh.Send(ctx, p2p.Envelope{ + if err := dataCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.BlockPart{ Height: rs.Height, // this tells peer that this part applies to us @@ -581,7 +587,7 @@ OUTER_LOOP: continue OUTER_LOOP } - r.gossipDataForCatchup(ctx, rs, prs, ps) + r.gossipDataForCatchup(ctx, rs, prs, ps, dataCh) continue OUTER_LOOP } @@ -608,7 +614,7 @@ OUTER_LOOP: propProto := rs.Proposal.ToProto() logger.Debug("sending proposal", "height", prs.Height, "round", prs.Round) - if err := r.dataCh.Send(ctx, p2p.Envelope{ + if err := dataCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.Proposal{ Proposal: *propProto, @@ -631,7 +637,7 @@ OUTER_LOOP: pPolProto := pPol.ToProto() logger.Debug("sending POL", "height", prs.Height, "round", prs.Round) - if err := r.dataCh.Send(ctx, p2p.Envelope{ + if err := dataCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.ProposalPOL{ Height: rs.Height, @@ -659,14 +665,14 @@ OUTER_LOOP: // pickSendVote picks a vote and sends it to the peer. It will return true if // there is a vote to send and false otherwise. -func (r *Reactor) pickSendVote(ctx context.Context, ps *PeerState, votes types.VoteSetReader) (bool, error) { +func (r *Reactor) pickSendVote(ctx context.Context, ps *PeerState, votes types.VoteSetReader, voteCh *p2p.Channel) (bool, error) { vote, ok := ps.PickVoteToSend(votes) if !ok { return false, nil } r.logger.Debug("sending vote message", "ps", ps, "vote", vote) - if err := r.voteCh.Send(ctx, p2p.Envelope{ + if err := voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.Vote{ Vote: vote.ToProto(), @@ -687,12 +693,13 @@ func (r *Reactor) gossipVotesForHeight( rs *cstypes.RoundState, prs *cstypes.PeerRoundState, ps *PeerState, + voteCh *p2p.Channel, ) (bool, error) { logger := r.logger.With("height", prs.Height).With("peer", ps.peerID) // if there are lastCommits to send... if prs.Step == cstypes.RoundStepNewHeight { - if ok, err := r.pickSendVote(ctx, ps, rs.LastCommit); err != nil { + if ok, err := r.pickSendVote(ctx, ps, rs.LastCommit, voteCh); err != nil { return false, err } else if ok { logger.Debug("picked rs.LastCommit to send") @@ -704,7 +711,7 @@ func (r *Reactor) gossipVotesForHeight( // if there are POL prevotes to send... if prs.Step <= cstypes.RoundStepPropose && prs.Round != -1 && prs.Round <= rs.Round && prs.ProposalPOLRound != -1 { if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil { - if ok, err := r.pickSendVote(ctx, ps, polPrevotes); err != nil { + if ok, err := r.pickSendVote(ctx, ps, polPrevotes, voteCh); err != nil { return false, err } else if ok { logger.Debug("picked rs.Prevotes(prs.ProposalPOLRound) to send", "round", prs.ProposalPOLRound) @@ -715,7 +722,7 @@ func (r *Reactor) gossipVotesForHeight( // if there are prevotes to send... if prs.Step <= cstypes.RoundStepPrevoteWait && prs.Round != -1 && prs.Round <= rs.Round { - if ok, err := r.pickSendVote(ctx, ps, rs.Votes.Prevotes(prs.Round)); err != nil { + if ok, err := r.pickSendVote(ctx, ps, rs.Votes.Prevotes(prs.Round), voteCh); err != nil { return false, err } else if ok { logger.Debug("picked rs.Prevotes(prs.Round) to send", "round", prs.Round) @@ -725,7 +732,7 @@ func (r *Reactor) gossipVotesForHeight( // if there are precommits to send... if prs.Step <= cstypes.RoundStepPrecommitWait && prs.Round != -1 && prs.Round <= rs.Round { - if ok, err := r.pickSendVote(ctx, ps, rs.Votes.Precommits(prs.Round)); err != nil { + if ok, err := r.pickSendVote(ctx, ps, rs.Votes.Precommits(prs.Round), voteCh); err != nil { return false, err } else if ok { logger.Debug("picked rs.Precommits(prs.Round) to send", "round", prs.Round) @@ -735,7 +742,7 @@ func (r *Reactor) gossipVotesForHeight( // if there are prevotes to send...(which are needed because of validBlock mechanism) if prs.Round != -1 && prs.Round <= rs.Round { - if ok, err := r.pickSendVote(ctx, ps, rs.Votes.Prevotes(prs.Round)); err != nil { + if ok, err := r.pickSendVote(ctx, ps, rs.Votes.Prevotes(prs.Round), voteCh); err != nil { return false, err } else if ok { logger.Debug("picked rs.Prevotes(prs.Round) to send", "round", prs.Round) @@ -746,7 +753,7 @@ func (r *Reactor) gossipVotesForHeight( // if there are POLPrevotes to send... if prs.ProposalPOLRound != -1 { if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil { - if ok, err := r.pickSendVote(ctx, ps, polPrevotes); err != nil { + if ok, err := r.pickSendVote(ctx, ps, polPrevotes, voteCh); err != nil { return false, err } else if ok { logger.Debug("picked rs.Prevotes(prs.ProposalPOLRound) to send", "round", prs.ProposalPOLRound) @@ -758,7 +765,7 @@ func (r *Reactor) gossipVotesForHeight( return false, nil } -func (r *Reactor) gossipVotesRoutine(ctx context.Context, ps *PeerState) { +func (r *Reactor) gossipVotesRoutine(ctx context.Context, ps *PeerState, voteCh *p2p.Channel) { logger := r.logger.With("peer", ps.peerID) // XXX: simple hack to throttle logs upon sleep @@ -790,7 +797,7 @@ func (r *Reactor) gossipVotesRoutine(ctx context.Context, ps *PeerState) { // if height matches, then send LastCommit, Prevotes, and Precommits if rs.Height == prs.Height { - if ok, err := r.gossipVotesForHeight(ctx, rs, prs, ps); err != nil { + if ok, err := r.gossipVotesForHeight(ctx, rs, prs, ps, voteCh); err != nil { return } else if ok { continue @@ -799,7 +806,7 @@ func (r *Reactor) gossipVotesRoutine(ctx context.Context, ps *PeerState) { // special catchup logic -- if peer is lagging by height 1, send LastCommit if prs.Height != 0 && rs.Height == prs.Height+1 { - if ok, err := r.pickSendVote(ctx, ps, rs.LastCommit); err != nil { + if ok, err := r.pickSendVote(ctx, ps, rs.LastCommit, voteCh); err != nil { return } else if ok { logger.Debug("picked rs.LastCommit to send", "height", prs.Height) @@ -813,7 +820,7 @@ func (r *Reactor) gossipVotesRoutine(ctx context.Context, ps *PeerState) { // Load the block commit for prs.Height, which contains precommit // signatures for prs.Height. if commit := r.state.blockStore.LoadBlockCommit(prs.Height); commit != nil { - if ok, err := r.pickSendVote(ctx, ps, commit); err != nil { + if ok, err := r.pickSendVote(ctx, ps, commit, voteCh); err != nil { return } else if ok { logger.Debug("picked Catchup commit to send", "height", prs.Height) @@ -847,7 +854,7 @@ func (r *Reactor) gossipVotesRoutine(ctx context.Context, ps *PeerState) { // NOTE: `queryMaj23Routine` has a simple crude design since it only comes // into play for liveness when there's a signature DDoS attack happening. -func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState) { +func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState, stateCh *p2p.Channel) { timer := time.NewTimer(0) defer timer.Stop() @@ -883,7 +890,7 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState) { // maybe send Height/Round/Prevotes if maj23, ok := rs.Votes.Prevotes(prs.Round).TwoThirdsMajority(); ok { - if err := r.stateCh.Send(ctx, p2p.Envelope{ + if err := stateCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.VoteSetMaj23{ Height: prs.Height, @@ -904,7 +911,7 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState) { // maybe send Height/Round/ProposalPOL if maj23, ok := rs.Votes.Prevotes(prs.ProposalPOLRound).TwoThirdsMajority(); ok { - if err := r.stateCh.Send(ctx, p2p.Envelope{ + if err := stateCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.VoteSetMaj23{ Height: prs.Height, @@ -925,7 +932,7 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState) { // maybe send Height/Round/Precommits if maj23, ok := rs.Votes.Precommits(prs.Round).TwoThirdsMajority(); ok { - if err := r.stateCh.Send(ctx, p2p.Envelope{ + if err := stateCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.VoteSetMaj23{ Height: prs.Height, @@ -950,7 +957,7 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState) { if prs.Height <= r.state.blockStore.Height() && prs.Height >= r.state.blockStore.Base() { // maybe send Height/CatchupCommitRound/CatchupCommit if commit := r.state.LoadCommit(prs.Height); commit != nil { - if err := r.stateCh.Send(ctx, p2p.Envelope{ + if err := stateCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.VoteSetMaj23{ Height: prs.Height, @@ -983,7 +990,7 @@ func (r *Reactor) queryMaj23Routine(ctx context.Context, ps *PeerState) { // be the case, and we spawn all the relevant goroutine to broadcast messages to // the peer. During peer removal, we remove the peer for our set of peers and // signal to all spawned goroutines to gracefully exit in a non-blocking manner. -func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate) { +func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate, chans channelBundle) { r.logger.Debug("received peer update", "peer", peerUpdate.NodeID, "status", peerUpdate.Status) r.mtx.Lock() @@ -1024,14 +1031,14 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda return } // start goroutines for this peer - go r.gossipDataRoutine(ctx, ps) - go r.gossipVotesRoutine(ctx, ps) - go r.queryMaj23Routine(ctx, ps) + go r.gossipDataRoutine(ctx, ps, chans.data) + go r.gossipVotesRoutine(ctx, ps, chans.vote) + go r.queryMaj23Routine(ctx, ps, chans.state) // Send our state to the peer. If we're block-syncing, broadcast a // RoundStepMessage later upon SwitchToConsensus(). if !r.WaitSync() { - go func() { _ = r.sendNewRoundStepMessage(ctx, ps.peerID) }() + go func() { _ = r.sendNewRoundStepMessage(ctx, ps.peerID, chans.state) }() } }() @@ -1058,7 +1065,7 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda // If we fail to find the peer state for the envelope sender, we perform a no-op // and return. This can happen when we process the envelope after the peer is // removed. -func (r *Reactor) handleStateMessage(ctx context.Context, envelope *p2p.Envelope, msgI Message) error { +func (r *Reactor) handleStateMessage(ctx context.Context, envelope *p2p.Envelope, msgI Message, voteSetCh *p2p.Channel) error { ps, ok := r.GetPeerState(envelope.From) if !ok || ps == nil { r.logger.Debug("failed to find peer state", "peer", envelope.From, "ch_id", "StateChannel") @@ -1128,7 +1135,7 @@ func (r *Reactor) handleStateMessage(ctx context.Context, envelope *p2p.Envelope eMsg.Votes = *votesProto } - if err := r.voteSetBitsCh.Send(ctx, p2p.Envelope{ + if err := voteSetCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: eMsg, }); err != nil { @@ -1296,7 +1303,7 @@ func (r *Reactor) handleVoteSetBitsMessage(ctx context.Context, envelope *p2p.En // the p2p channel. // // NOTE: We block on consensus state for proposals, block parts, and votes. -func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelope *p2p.Envelope) (err error) { +func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelope *p2p.Envelope, chans channelBundle) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("panic in processing message: %v", e) @@ -1327,17 +1334,13 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop switch chID { case StateChannel: - err = r.handleStateMessage(ctx, envelope, msgI) - + err = r.handleStateMessage(ctx, envelope, msgI, chans.votSet) case DataChannel: err = r.handleDataMessage(ctx, envelope, msgI) - case VoteChannel: err = r.handleVoteMessage(ctx, envelope, msgI) - case VoteSetBitsChannel: err = r.handleVoteSetBitsMessage(ctx, envelope, msgI) - default: err = fmt.Errorf("unknown channel ID (%d) for envelope (%v)", chID, envelope) } @@ -1350,13 +1353,13 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop // execution will result in a PeerError being sent on the StateChannel. When // the reactor is stopped, we will catch the signal and close the p2p Channel // gracefully. -func (r *Reactor) processStateCh(ctx context.Context) { - iter := r.stateCh.Receive(ctx) +func (r *Reactor) processStateCh(ctx context.Context, chans channelBundle) { + iter := chans.state.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.stateCh.ID, envelope); err != nil { - r.logger.Error("failed to process message", "ch_id", r.stateCh.ID, "envelope", envelope, "err", err) - if serr := r.stateCh.SendError(ctx, p2p.PeerError{ + if err := r.handleMessage(ctx, chans.state.ID, envelope, chans); err != nil { + r.logger.Error("failed to process message", "ch_id", chans.state.ID, "envelope", envelope, "err", err) + if serr := chans.state.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -1371,13 +1374,13 @@ func (r *Reactor) processStateCh(ctx context.Context) { // execution will result in a PeerError being sent on the DataChannel. When // the reactor is stopped, we will catch the signal and close the p2p Channel // gracefully. -func (r *Reactor) processDataCh(ctx context.Context) { - iter := r.dataCh.Receive(ctx) +func (r *Reactor) processDataCh(ctx context.Context, chans channelBundle) { + iter := chans.data.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.dataCh.ID, envelope); err != nil { - r.logger.Error("failed to process message", "ch_id", r.dataCh.ID, "envelope", envelope, "err", err) - if serr := r.dataCh.SendError(ctx, p2p.PeerError{ + if err := r.handleMessage(ctx, chans.data.ID, envelope, chans); err != nil { + r.logger.Error("failed to process message", "ch_id", chans.data.ID, "envelope", envelope, "err", err) + if serr := chans.data.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -1392,13 +1395,13 @@ func (r *Reactor) processDataCh(ctx context.Context) { // execution will result in a PeerError being sent on the VoteChannel. When // the reactor is stopped, we will catch the signal and close the p2p Channel // gracefully. -func (r *Reactor) processVoteCh(ctx context.Context) { - iter := r.voteCh.Receive(ctx) +func (r *Reactor) processVoteCh(ctx context.Context, chans channelBundle) { + iter := chans.vote.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.voteCh.ID, envelope); err != nil { - r.logger.Error("failed to process message", "ch_id", r.voteCh.ID, "envelope", envelope, "err", err) - if serr := r.voteCh.SendError(ctx, p2p.PeerError{ + if err := r.handleMessage(ctx, chans.vote.ID, envelope, chans); err != nil { + r.logger.Error("failed to process message", "ch_id", chans.vote.ID, "envelope", envelope, "err", err) + if serr := chans.vote.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -1413,18 +1416,18 @@ func (r *Reactor) processVoteCh(ctx context.Context) { // execution will result in a PeerError being sent on the VoteSetBitsChannel. // When the reactor is stopped, we will catch the signal and close the p2p // Channel gracefully. -func (r *Reactor) processVoteSetBitsCh(ctx context.Context) { - iter := r.voteSetBitsCh.Receive(ctx) +func (r *Reactor) processVoteSetBitsCh(ctx context.Context, chans channelBundle) { + iter := chans.votSet.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.voteSetBitsCh.ID, envelope); err != nil { + if err := r.handleMessage(ctx, chans.votSet.ID, envelope, chans); err != nil { if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { return } - r.logger.Error("failed to process message", "ch_id", r.voteSetBitsCh.ID, "envelope", envelope, "err", err) - if serr := r.voteSetBitsCh.SendError(ctx, p2p.PeerError{ + r.logger.Error("failed to process message", "ch_id", chans.votSet.ID, "envelope", envelope, "err", err) + if serr := chans.votSet.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -1437,18 +1440,18 @@ func (r *Reactor) processVoteSetBitsCh(ctx context.Context) { // processPeerUpdates initiates a blocking process where we listen for and handle // PeerUpdate messages. When the reactor is stopped, we will catch the signal and // close the p2p PeerUpdatesCh gracefully. -func (r *Reactor) processPeerUpdates(ctx context.Context) { +func (r *Reactor) processPeerUpdates(ctx context.Context, peerUpdates *p2p.PeerUpdates, chans channelBundle) { for { select { case <-ctx.Done(): return - case peerUpdate := <-r.peerUpdates.Updates(): - r.processPeerUpdate(ctx, peerUpdate) + case peerUpdate := <-peerUpdates.Updates(): + r.processPeerUpdate(ctx, peerUpdate, chans) } } } -func (r *Reactor) peerStatsRoutine(ctx context.Context) { +func (r *Reactor) peerStatsRoutine(ctx context.Context, peerUpdates *p2p.PeerUpdates) { for { if !r.IsRunning() { r.logger.Info("stopping peerStatsRoutine") @@ -1466,7 +1469,7 @@ func (r *Reactor) peerStatsRoutine(ctx context.Context) { switch msg.Msg.(type) { case *VoteMessage: if numVotes := ps.RecordVote(); numVotes%votesToContributeToBecomeGoodPeer == 0 { - r.peerUpdates.SendUpdate(ctx, p2p.PeerUpdate{ + peerUpdates.SendUpdate(ctx, p2p.PeerUpdate{ NodeID: msg.PeerID, Status: p2p.PeerStatusGood, }) @@ -1474,7 +1477,7 @@ func (r *Reactor) peerStatsRoutine(ctx context.Context) { case *BlockPartMessage: if numParts := ps.RecordBlockPart(); numParts%blocksToContributeToBecomeGoodPeer == 0 { - r.peerUpdates.SendUpdate(ctx, p2p.PeerUpdate{ + peerUpdates.SendUpdate(ctx, p2p.PeerUpdate{ NodeID: msg.PeerID, Status: p2p.PeerStatusGood, }) diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index 886e3794a..9c6af5c5b 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -104,16 +104,15 @@ func setup( for nodeID, node := range rts.network.Nodes { state := states[i] - reactor, err := NewReactor(ctx, + reactor := NewReactor( state.logger.With("node", nodeID), state, chCreator(nodeID), - node.MakePeerUpdates(ctx, t), + func(ctx context.Context) *p2p.PeerUpdates { return node.MakePeerUpdates(ctx, t) }, state.eventBus, true, NopMetrics(), ) - require.NoError(t, err) blocksSub, err := state.eventBus.SubscribeWithArgs(ctx, tmpubsub.SubscribeArgs{ ClientID: testSubscriber, diff --git a/internal/evidence/reactor.go b/internal/evidence/reactor.go index c52e7e32b..4809df32e 100644 --- a/internal/evidence/reactor.go +++ b/internal/evidence/reactor.go @@ -47,9 +47,9 @@ type Reactor struct { service.BaseService logger log.Logger - evpool *Pool - evidenceCh *p2p.Channel - peerUpdates *p2p.PeerUpdates + evpool *Pool + chCreator p2p.ChannelCreator + peerEvents p2p.PeerEventSubscriber mtx sync.Mutex @@ -60,28 +60,22 @@ type Reactor struct { // service.Service interface. It accepts a p2p Channel dedicated for handling // envelopes with EvidenceList messages. func NewReactor( - ctx context.Context, logger log.Logger, chCreator p2p.ChannelCreator, - peerUpdates *p2p.PeerUpdates, + peerEvents p2p.PeerEventSubscriber, evpool *Pool, -) (*Reactor, error) { - evidenceCh, err := chCreator(ctx, GetChannelDescriptor()) - if err != nil { - return nil, err - } - +) *Reactor { r := &Reactor{ logger: logger, evpool: evpool, - evidenceCh: evidenceCh, - peerUpdates: peerUpdates, + chCreator: chCreator, + peerEvents: peerEvents, peerRoutines: make(map[types.NodeID]context.CancelFunc), } r.BaseService = *service.NewBaseService(logger, "Evidence", r) - return r, err + return r } // OnStart starts separate go routines for each p2p Channel and listens for @@ -89,18 +83,20 @@ func NewReactor( // messages on that p2p channel accordingly. The caller must be sure to execute // OnStop to ensure the outbound p2p Channels are closed. No error is returned. func (r *Reactor) OnStart(ctx context.Context) error { - go r.processEvidenceCh(ctx) - go r.processPeerUpdates(ctx) + ch, err := r.chCreator(ctx, GetChannelDescriptor()) + if err != nil { + return err + } + + go r.processEvidenceCh(ctx, ch) + go r.processPeerUpdates(ctx, r.peerEvents(ctx), ch) return nil } // OnStop stops the reactor by signaling to all spawned goroutines to exit and // blocking until they all exit. -func (r *Reactor) OnStop() { - // Close the evidence db - r.evpool.Close() -} +func (r *Reactor) OnStop() { r.evpool.Close() } // handleEvidenceMessage handles envelopes sent from peers on the EvidenceChannel. // It returns an error only if the Envelope.Message is unknown for this channel @@ -164,13 +160,13 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop // processEvidenceCh implements a blocking event loop where we listen for p2p // Envelope messages from the evidenceCh. -func (r *Reactor) processEvidenceCh(ctx context.Context) { - iter := r.evidenceCh.Receive(ctx) +func (r *Reactor) processEvidenceCh(ctx context.Context, evidenceCh *p2p.Channel) { + iter := evidenceCh.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.evidenceCh.ID, envelope); err != nil { - r.logger.Error("failed to process message", "ch_id", r.evidenceCh.ID, "envelope", envelope, "err", err) - if serr := r.evidenceCh.SendError(ctx, p2p.PeerError{ + if err := r.handleMessage(ctx, evidenceCh.ID, envelope); err != nil { + r.logger.Error("failed to process message", "ch_id", evidenceCh.ID, "envelope", envelope, "err", err) + if serr := evidenceCh.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -191,7 +187,7 @@ func (r *Reactor) processEvidenceCh(ctx context.Context) { // connects/disconnects frequently from the broadcasting peer(s). // // REF: https://github.com/tendermint/tendermint/issues/4727 -func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate) { +func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate, evidenceCh *p2p.Channel) { r.logger.Debug("received peer update", "peer", peerUpdate.NodeID, "status", peerUpdate.Status) r.mtx.Lock() @@ -214,7 +210,7 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda if !ok { pctx, pcancel := context.WithCancel(ctx) r.peerRoutines[peerUpdate.NodeID] = pcancel - go r.broadcastEvidenceLoop(pctx, peerUpdate.NodeID) + go r.broadcastEvidenceLoop(pctx, peerUpdate.NodeID, evidenceCh) } case p2p.PeerStatusDown: @@ -232,11 +228,11 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda // processPeerUpdates initiates a blocking process where we listen for and handle // PeerUpdate messages. When the reactor is stopped, we will catch the signal and // close the p2p PeerUpdatesCh gracefully. -func (r *Reactor) processPeerUpdates(ctx context.Context) { +func (r *Reactor) processPeerUpdates(ctx context.Context, peerUpdates *p2p.PeerUpdates, evidenceCh *p2p.Channel) { for { select { - case peerUpdate := <-r.peerUpdates.Updates(): - r.processPeerUpdate(ctx, peerUpdate) + case peerUpdate := <-peerUpdates.Updates(): + r.processPeerUpdate(ctx, peerUpdate, evidenceCh) case <-ctx.Done(): return } @@ -254,7 +250,7 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { // that the peer has already received or may not be ready for. // // REF: https://github.com/tendermint/tendermint/issues/4727 -func (r *Reactor) broadcastEvidenceLoop(ctx context.Context, peerID types.NodeID) { +func (r *Reactor) broadcastEvidenceLoop(ctx context.Context, peerID types.NodeID, evidenceCh *p2p.Channel) { var next *clist.CElement defer func() { @@ -301,7 +297,7 @@ func (r *Reactor) broadcastEvidenceLoop(ctx context.Context, peerID types.NodeID // peer may receive this piece of evidence multiple times if it added and // removed frequently from the broadcasting peer. - if err := r.evidenceCh.Send(ctx, p2p.Envelope{ + if err := evidenceCh.Send(ctx, p2p.Envelope{ To: peerID, Message: evProto, }); err != nil { diff --git a/internal/evidence/reactor_test.go b/internal/evidence/reactor_test.go index 0b2c2fb3b..2fdfa8c60 100644 --- a/internal/evidence/reactor_test.go +++ b/internal/evidence/reactor_test.go @@ -92,21 +92,20 @@ func setup(ctx context.Context, t *testing.T, stateStores []sm.Store, chBuf uint require.NoError(t, err) rts.peerChans[nodeID] = make(chan p2p.PeerUpdate) - rts.peerUpdates[nodeID] = p2p.NewPeerUpdates(rts.peerChans[nodeID], 1) - rts.network.Nodes[nodeID].PeerManager.Register(ctx, rts.peerUpdates[nodeID]) + pu := p2p.NewPeerUpdates(rts.peerChans[nodeID], 1) + rts.peerUpdates[nodeID] = pu + rts.network.Nodes[nodeID].PeerManager.Register(ctx, pu) rts.nodes = append(rts.nodes, rts.network.Nodes[nodeID]) chCreator := func(ctx context.Context, chdesc *p2p.ChannelDescriptor) (*p2p.Channel, error) { return rts.evidenceChannels[nodeID], nil } - rts.reactors[nodeID], err = evidence.NewReactor( - ctx, + rts.reactors[nodeID] = evidence.NewReactor( logger, chCreator, - rts.peerUpdates[nodeID], + func(ctx context.Context) *p2p.PeerUpdates { return pu }, rts.pools[nodeID]) - require.NoError(t, err) require.NoError(t, rts.reactors[nodeID].Start(ctx)) require.True(t, rts.reactors[nodeID].IsRunning()) diff --git a/internal/mempool/reactor.go b/internal/mempool/reactor.go index 816589c9b..8f83f5006 100644 --- a/internal/mempool/reactor.go +++ b/internal/mempool/reactor.go @@ -40,13 +40,9 @@ type Reactor struct { mempool *TxMempool ids *IDs - // XXX: Currently, this is the only way to get information about a peer. Ideally, - // we rely on message-oriented communication to get necessary peer data. - // ref: https://github.com/tendermint/tendermint/issues/5670 - peerMgr PeerManager - - mempoolCh *p2p.Channel - peerUpdates *p2p.PeerUpdates + getPeerHeight func(types.NodeID) int64 + peerEvents p2p.PeerEventSubscriber + chCreator p2p.ChannelCreator // observePanic is a function for observing panics that were recovered in methods on // Reactor. observePanic is called with the recovered value. @@ -58,34 +54,27 @@ type Reactor struct { // NewReactor returns a reference to a new reactor. func NewReactor( - ctx context.Context, logger log.Logger, cfg *config.MempoolConfig, - peerMgr PeerManager, txmp *TxMempool, chCreator p2p.ChannelCreator, - peerUpdates *p2p.PeerUpdates, -) (*Reactor, error) { - - ch, err := chCreator(ctx, getChannelDescriptor(cfg)) - if err != nil { - return nil, err - } - + peerEvents p2p.PeerEventSubscriber, + getPeerHeight func(types.NodeID) int64, +) *Reactor { r := &Reactor{ - logger: logger, - cfg: cfg, - peerMgr: peerMgr, - mempool: txmp, - ids: NewMempoolIDs(), - mempoolCh: ch, - peerUpdates: peerUpdates, - peerRoutines: make(map[types.NodeID]context.CancelFunc), - observePanic: defaultObservePanic, + logger: logger, + cfg: cfg, + mempool: txmp, + ids: NewMempoolIDs(), + chCreator: chCreator, + peerEvents: peerEvents, + getPeerHeight: getPeerHeight, + peerRoutines: make(map[types.NodeID]context.CancelFunc), + observePanic: defaultObservePanic, } r.BaseService = *service.NewBaseService(logger, "Mempool", r) - return r, nil + return r } func defaultObservePanic(r interface{}) {} @@ -119,8 +108,13 @@ func (r *Reactor) OnStart(ctx context.Context) error { r.logger.Info("tx broadcasting is disabled") } - go r.processMempoolCh(ctx) - go r.processPeerUpdates(ctx) + ch, err := r.chCreator(ctx, getChannelDescriptor(r.cfg)) + if err != nil { + return err + } + + go r.processMempoolCh(ctx, ch) + go r.processPeerUpdates(ctx, r.peerEvents(ctx), ch) return nil } @@ -203,13 +197,13 @@ func (r *Reactor) handleMessage(ctx context.Context, chID p2p.ChannelID, envelop // processMempoolCh implements a blocking event loop where we listen for p2p // Envelope messages from the mempoolCh. -func (r *Reactor) processMempoolCh(ctx context.Context) { - iter := r.mempoolCh.Receive(ctx) +func (r *Reactor) processMempoolCh(ctx context.Context, mempoolCh *p2p.Channel) { + iter := mempoolCh.Receive(ctx) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, r.mempoolCh.ID, envelope); err != nil { - r.logger.Error("failed to process message", "ch_id", r.mempoolCh.ID, "envelope", envelope, "err", err) - if serr := r.mempoolCh.SendError(ctx, p2p.PeerError{ + if err := r.handleMessage(ctx, mempoolCh.ID, envelope); err != nil { + r.logger.Error("failed to process message", "ch_id", mempoolCh.ID, "envelope", envelope, "err", err) + if serr := mempoolCh.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -224,7 +218,7 @@ func (r *Reactor) processMempoolCh(ctx context.Context) { // goroutine or not. If not, we start one for the newly added peer. For down or // removed peers, we remove the peer from the mempool peer ID set and signal to // stop the tx broadcasting goroutine. -func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate) { +func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpdate, mempoolCh *p2p.Channel) { r.logger.Debug("received peer update", "peer", peerUpdate.NodeID, "status", peerUpdate.Status) r.mtx.Lock() @@ -252,7 +246,7 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda r.ids.ReserveForPeer(peerUpdate.NodeID) // start a broadcast routine ensuring all txs are forwarded to the peer - go r.broadcastTxRoutine(pctx, peerUpdate.NodeID) + go r.broadcastTxRoutine(pctx, peerUpdate.NodeID, mempoolCh) } } @@ -273,18 +267,18 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda // processPeerUpdates initiates a blocking process where we listen for and handle // PeerUpdate messages. When the reactor is stopped, we will catch the signal and // close the p2p PeerUpdatesCh gracefully. -func (r *Reactor) processPeerUpdates(ctx context.Context) { +func (r *Reactor) processPeerUpdates(ctx context.Context, peerUpdates *p2p.PeerUpdates, mempoolCh *p2p.Channel) { for { select { case <-ctx.Done(): return - case peerUpdate := <-r.peerUpdates.Updates(): - r.processPeerUpdate(ctx, peerUpdate) + case peerUpdate := <-peerUpdates.Updates(): + r.processPeerUpdate(ctx, peerUpdate, mempoolCh) } } } -func (r *Reactor) broadcastTxRoutine(ctx context.Context, peerID types.NodeID) { +func (r *Reactor) broadcastTxRoutine(ctx context.Context, peerID types.NodeID, mempoolCh *p2p.Channel) { peerMempoolID := r.ids.GetForPeer(peerID) var nextGossipTx *clist.CElement @@ -325,8 +319,8 @@ func (r *Reactor) broadcastTxRoutine(ctx context.Context, peerID types.NodeID) { memTx := nextGossipTx.Value.(*WrappedTx) - if r.peerMgr != nil { - height := r.peerMgr.GetHeight(peerID) + if r.getPeerHeight != nil { + height := r.getPeerHeight(peerID) if height > 0 && height < memTx.height-1 { // allow for a lag of one block time.Sleep(PeerCatchupSleepIntervalMS * time.Millisecond) @@ -339,7 +333,7 @@ func (r *Reactor) broadcastTxRoutine(ctx context.Context, peerID types.NodeID) { if ok := r.mempool.txStore.TxHasPeer(memTx.hash, peerMempoolID); !ok { // Send the mempool tx to the corresponding peer. Note, the peer may be // behind and thus would not be able to process the mempool tx correctly. - if err := r.mempoolCh.Send(ctx, p2p.Envelope{ + if err := mempoolCh.Send(ctx, p2p.Envelope{ To: peerID, Message: &protomem.Txs{ Txs: [][]byte{memTx.tx}, diff --git a/internal/mempool/reactor_test.go b/internal/mempool/reactor_test.go index 64a8adca1..82a97aeec 100644 --- a/internal/mempool/reactor_test.go +++ b/internal/mempool/reactor_test.go @@ -79,17 +79,14 @@ func setupReactors(ctx context.Context, t *testing.T, logger log.Logger, numNode return rts.mempoolChannels[nodeID], nil } - rts.reactors[nodeID], err = NewReactor( - ctx, + rts.reactors[nodeID] = NewReactor( rts.logger.With("nodeID", nodeID), cfg.Mempool, - rts.network.Nodes[nodeID].PeerManager, mempool, chCreator, - rts.peerUpdates[nodeID], + func(ctx context.Context) *p2p.PeerUpdates { return rts.peerUpdates[nodeID] }, + rts.network.Nodes[nodeID].PeerManager.GetHeight, ) - - require.NoError(t, err) rts.nodes = append(rts.nodes, nodeID) require.NoError(t, rts.reactors[nodeID].Start(ctx)) @@ -179,7 +176,7 @@ func TestReactorBroadcastDoesNotPanic(t *testing.T) { // run the router rts.start(ctx, t) - go primaryReactor.broadcastTxRoutine(ctx, secondary) + go primaryReactor.broadcastTxRoutine(ctx, secondary, rts.mempoolChannels[primary]) wg := &sync.WaitGroup{} for i := 0; i < 50; i++ { diff --git a/internal/p2p/p2ptest/network.go b/internal/p2p/p2ptest/network.go index fdfc0d45c..6016ce0a5 100644 --- a/internal/p2p/p2ptest/network.go +++ b/internal/p2p/p2ptest/network.go @@ -259,7 +259,6 @@ func (n *Network) MakeNode(ctx context.Context, t *testing.T, opts NodeOptions) require.NoError(t, err) router, err := p2p.NewRouter( - ctx, n.logger, p2p.NopMetrics(), nodeInfo, diff --git a/internal/p2p/peermanager.go b/internal/p2p/peermanager.go index 4044ad569..756551a49 100644 --- a/internal/p2p/peermanager.go +++ b/internal/p2p/peermanager.go @@ -828,6 +828,11 @@ func (m *PeerManager) Advertise(peerID types.NodeID, limit uint16) []NodeAddress return addresses } +// PeerEventSubscriber describes the type of the subscription method, to assist +// in isolating reactors specific construction and lifecycle from the +// peer manager. +type PeerEventSubscriber func(context.Context) *PeerUpdates + // Subscribe subscribes to peer updates. The caller must consume the peer // updates in a timely fashion and close the subscription when done, otherwise // the PeerManager will halt. diff --git a/internal/p2p/pex/reactor.go b/internal/p2p/pex/reactor.go index 178524af2..1c80763ee 100644 --- a/internal/p2p/pex/reactor.go +++ b/internal/p2p/pex/reactor.go @@ -80,9 +80,8 @@ type Reactor struct { logger log.Logger peerManager *p2p.PeerManager - pexCh *p2p.Channel - peerUpdates *p2p.PeerUpdates - + chCreator p2p.ChannelCreator + peerEvents p2p.PeerEventSubscriber // list of available peers to loop through and send peer requests to availablePeers map[types.NodeID]struct{} @@ -105,30 +104,23 @@ type Reactor struct { // NewReactor returns a reference to a new reactor. func NewReactor( - ctx context.Context, logger log.Logger, peerManager *p2p.PeerManager, channelCreator p2p.ChannelCreator, - peerUpdates *p2p.PeerUpdates, -) (*Reactor, error) { - - channel, err := channelCreator(ctx, ChannelDescriptor()) - if err != nil { - return nil, err - } - + peerEvents p2p.PeerEventSubscriber, +) *Reactor { r := &Reactor{ logger: logger, peerManager: peerManager, - pexCh: channel, - peerUpdates: peerUpdates, + chCreator: channelCreator, + peerEvents: peerEvents, availablePeers: make(map[types.NodeID]struct{}), requestsSent: make(map[types.NodeID]struct{}), lastReceivedRequests: make(map[types.NodeID]time.Time), } r.BaseService = *service.NewBaseService(logger, "PEX", r) - return r, nil + return r } // OnStart starts separate go routines for each p2p Channel and listens for @@ -136,8 +128,14 @@ func NewReactor( // messages on that p2p channel accordingly. The caller must be sure to execute // OnStop to ensure the outbound p2p Channels are closed. func (r *Reactor) OnStart(ctx context.Context) error { - go r.processPexCh(ctx) - go r.processPeerUpdates(ctx) + channel, err := r.chCreator(ctx, ChannelDescriptor()) + if err != nil { + return err + } + + peerUpdates := r.peerEvents(ctx) + go r.processPexCh(ctx, channel) + go r.processPeerUpdates(ctx, peerUpdates) return nil } @@ -147,11 +145,11 @@ func (r *Reactor) OnStop() {} // processPexCh implements a blocking event loop where we listen for p2p // Envelope messages from the pexCh. -func (r *Reactor) processPexCh(ctx context.Context) { +func (r *Reactor) processPexCh(ctx context.Context, pexCh *p2p.Channel) { incoming := make(chan *p2p.Envelope) go func() { defer close(incoming) - iter := r.pexCh.Receive(ctx) + iter := pexCh.Receive(ctx) for iter.Next(ctx) { select { case <-ctx.Done(): @@ -177,7 +175,7 @@ func (r *Reactor) processPexCh(ctx context.Context) { case <-timer.C: // Send a request for more peer addresses. - if err := r.sendRequestForPeers(ctx); err != nil { + if err := r.sendRequestForPeers(ctx, pexCh); err != nil { return // TODO(creachadair): Do we really want to stop processing the PEX // channel just because of an error here? @@ -192,11 +190,11 @@ func (r *Reactor) processPexCh(ctx context.Context) { } // A request from another peer, or a response to one of our requests. - dur, err := r.handlePexMessage(ctx, envelope) + dur, err := r.handlePexMessage(ctx, envelope, pexCh) if err != nil { r.logger.Error("failed to process message", - "ch_id", r.pexCh.ID, "envelope", envelope, "err", err) - if serr := r.pexCh.SendError(ctx, p2p.PeerError{ + "ch_id", pexCh.ID, "envelope", envelope, "err", err) + if serr := pexCh.SendError(ctx, p2p.PeerError{ NodeID: envelope.From, Err: err, }); serr != nil { @@ -213,12 +211,12 @@ func (r *Reactor) processPexCh(ctx context.Context) { // processPeerUpdates initiates a blocking process where we listen for and handle // PeerUpdate messages. When the reactor is stopped, we will catch the signal and // close the p2p PeerUpdatesCh gracefully. -func (r *Reactor) processPeerUpdates(ctx context.Context) { +func (r *Reactor) processPeerUpdates(ctx context.Context, peerUpdates *p2p.PeerUpdates) { for { select { case <-ctx.Done(): return - case peerUpdate := <-r.peerUpdates.Updates(): + case peerUpdate := <-peerUpdates.Updates(): r.processPeerUpdate(peerUpdate) } } @@ -227,7 +225,7 @@ func (r *Reactor) processPeerUpdates(ctx context.Context) { // handlePexMessage handles envelopes sent from peers on the PexChannel. // If an update was received, a new polling interval is returned; otherwise the // duration is 0. -func (r *Reactor) handlePexMessage(ctx context.Context, envelope *p2p.Envelope) (time.Duration, error) { +func (r *Reactor) handlePexMessage(ctx context.Context, envelope *p2p.Envelope, pexCh *p2p.Channel) (time.Duration, error) { logger := r.logger.With("peer", envelope.From) switch msg := envelope.Message.(type) { @@ -246,7 +244,7 @@ func (r *Reactor) handlePexMessage(ctx context.Context, envelope *p2p.Envelope) URL: addr.String(), } } - return 0, r.pexCh.Send(ctx, p2p.Envelope{ + return 0, pexCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: &protop2p.PexResponse{Addresses: pexAddresses}, }) @@ -310,7 +308,7 @@ func (r *Reactor) processPeerUpdate(peerUpdate p2p.PeerUpdate) { // that peer a request for more peer addresses. The chosen peer is moved into // the requestsSent bucket so that we will not attempt to contact them again // until they've replied or updated. -func (r *Reactor) sendRequestForPeers(ctx context.Context) error { +func (r *Reactor) sendRequestForPeers(ctx context.Context, pexCh *p2p.Channel) error { r.mtx.Lock() defer r.mtx.Unlock() if len(r.availablePeers) == 0 { @@ -325,7 +323,7 @@ func (r *Reactor) sendRequestForPeers(ctx context.Context) error { break } - if err := r.pexCh.Send(ctx, p2p.Envelope{ + if err := pexCh.Send(ctx, p2p.Envelope{ To: peerID, Message: &protop2p.PexRequest{}, }); err != nil { diff --git a/internal/p2p/pex/reactor_test.go b/internal/p2p/pex/reactor_test.go index 288755e19..325ea72ab 100644 --- a/internal/p2p/pex/reactor_test.go +++ b/internal/p2p/pex/reactor_test.go @@ -23,8 +23,8 @@ import ( const ( checkFrequency = 500 * time.Millisecond defaultBufferSize = 2 - shortWait = 10 * time.Second - longWait = 60 * time.Second + shortWait = 5 * time.Second + longWait = 20 * time.Second firstNode = 0 secondNode = 1 @@ -211,7 +211,8 @@ func TestReactorSmallPeerStoreInALargeNetwork(t *testing.T) { require.Eventually(t, func() bool { // nolint:scopelint return testNet.network.Nodes[nodeID].PeerManager.PeerRatio() >= 0.9 - }, longWait, checkFrequency) + }, longWait, checkFrequency, + "peer ratio is: %f", testNet.network.Nodes[nodeID].PeerManager.PeerRatio()) } } @@ -303,8 +304,7 @@ func setupSingle(ctx context.Context, t *testing.T) *singleTestReactor { return pexCh, nil } - reactor, err := pex.NewReactor(ctx, log.NewNopLogger(), peerManager, chCreator, peerUpdates) - require.NoError(t, err) + reactor := pex.NewReactor(log.NewNopLogger(), peerManager, chCreator, func(_ context.Context) *p2p.PeerUpdates { return peerUpdates }) require.NoError(t, reactor.Start(ctx)) t.Cleanup(reactor.Wait) @@ -381,6 +381,10 @@ func setupNetwork(ctx context.Context, t *testing.T, opts testOptions) *reactorT idx := 0 for nodeID := range rts.network.Nodes { + // make a copy to avoid getting hit by the range ref + // confusion: + nodeID := nodeID + rts.peerChans[nodeID] = make(chan p2p.PeerUpdate, chBuf) rts.peerUpdates[nodeID] = p2p.NewPeerUpdates(rts.peerChans[nodeID], chBuf) rts.network.Nodes[nodeID].PeerManager.Register(ctx, rts.peerUpdates[nodeID]) @@ -393,15 +397,12 @@ func setupNetwork(ctx context.Context, t *testing.T, opts testOptions) *reactorT if idx < opts.MockNodes { rts.mocks = append(rts.mocks, nodeID) } else { - var err error - rts.reactors[nodeID], err = pex.NewReactor( - ctx, + rts.reactors[nodeID] = pex.NewReactor( rts.logger.With("nodeID", nodeID), rts.network.Nodes[nodeID].PeerManager, chCreator, - rts.peerUpdates[nodeID], + func(_ context.Context) *p2p.PeerUpdates { return rts.peerUpdates[nodeID] }, ) - require.NoError(t, err) } rts.nodes = append(rts.nodes, nodeID) @@ -426,9 +427,10 @@ func setupNetwork(ctx context.Context, t *testing.T, opts testOptions) *reactorT func (r *reactorTestSuite) start(ctx context.Context, t *testing.T) { t.Helper() - for _, reactor := range r.reactors { + for name, reactor := range r.reactors { require.NoError(t, reactor.Start(ctx)) require.True(t, reactor.IsRunning()) + t.Log("started", name) } } @@ -451,15 +453,12 @@ func (r *reactorTestSuite) addNodes(ctx context.Context, t *testing.T, nodes int return r.pexChannels[nodeID], nil } - var err error - r.reactors[nodeID], err = pex.NewReactor( - ctx, + r.reactors[nodeID] = pex.NewReactor( r.logger.With("nodeID", nodeID), r.network.Nodes[nodeID].PeerManager, chCreator, - r.peerUpdates[nodeID], + func(_ context.Context) *p2p.PeerUpdates { return r.peerUpdates[nodeID] }, ) - require.NoError(t, err) r.nodes = append(r.nodes, nodeID) r.total++ } diff --git a/internal/p2p/router.go b/internal/p2p/router.go index 40c24d56b..025769592 100644 --- a/internal/p2p/router.go +++ b/internal/p2p/router.go @@ -177,7 +177,6 @@ type Router struct { // listening on appropriate interfaces, and will be closed by the Router when it // stops. func NewRouter( - ctx context.Context, logger log.Logger, metrics *Metrics, nodeInfo types.NodeInfo, @@ -215,13 +214,6 @@ func NewRouter( router.BaseService = service.NewBaseService(logger, "router", router) - qf, err := router.createQueueFactory(ctx) - if err != nil { - return nil, err - } - - router.queueFactory = qf - for _, transport := range transports { for _, protocol := range transport.Protocols() { if _, ok := router.protocolTransports[protocol]; !ok { @@ -941,8 +933,22 @@ func (r *Router) NodeInfo() types.NodeInfo { return r.nodeInfo.Copy() } +func (r *Router) setupQueueFactory(ctx context.Context) error { + qf, err := r.createQueueFactory(ctx) + if err != nil { + return err + } + + r.queueFactory = qf + return nil +} + // OnStart implements service.Service. func (r *Router) OnStart(ctx context.Context) error { + if err := r.setupQueueFactory(ctx); err != nil { + return err + } + for _, transport := range r.transports { for _, endpoint := range r.endpoints { if err := transport.Listen(endpoint); err != nil { diff --git a/internal/p2p/router_init_test.go b/internal/p2p/router_init_test.go index 19b4aa94c..d58c79487 100644 --- a/internal/p2p/router_init_test.go +++ b/internal/p2p/router_init_test.go @@ -23,29 +23,35 @@ func TestRouter_ConstructQueueFactory(t *testing.T) { t.Run("Default", func(t *testing.T) { require.Zero(t, os.Getenv("TM_P2P_QUEUE")) opts := RouterOptions{} - r, err := NewRouter(ctx, log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + r, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) require.NoError(t, err) + require.NoError(t, r.setupQueueFactory(ctx)) + _, ok := r.queueFactory(1).(*fifoQueue) require.True(t, ok) }) t.Run("Fifo", func(t *testing.T) { opts := RouterOptions{QueueType: queueTypeFifo} - r, err := NewRouter(ctx, log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + r, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) require.NoError(t, err) + require.NoError(t, r.setupQueueFactory(ctx)) + _, ok := r.queueFactory(1).(*fifoQueue) require.True(t, ok) }) t.Run("Priority", func(t *testing.T) { opts := RouterOptions{QueueType: queueTypePriority} - r, err := NewRouter(ctx, log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + r, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) require.NoError(t, err) + require.NoError(t, r.setupQueueFactory(ctx)) + q, ok := r.queueFactory(1).(*pqScheduler) require.True(t, ok) defer q.close() }) t.Run("NonExistant", func(t *testing.T) { opts := RouterOptions{QueueType: "fast"} - _, err := NewRouter(ctx, log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + _, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) require.Error(t, err) require.Contains(t, err.Error(), "fast") }) diff --git a/internal/p2p/router_test.go b/internal/p2p/router_test.go index 6142dc45f..5facfdaff 100644 --- a/internal/p2p/router_test.go +++ b/internal/p2p/router_test.go @@ -106,7 +106,6 @@ func TestRouter_Channel_Basic(t *testing.T) { require.NoError(t, err) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -409,7 +408,6 @@ func TestRouter_AcceptPeers(t *testing.T) { sub := peerManager.Subscribe(ctx) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -464,7 +462,6 @@ func TestRouter_AcceptPeers_Error(t *testing.T) { require.NoError(t, err) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -502,7 +499,6 @@ func TestRouter_AcceptPeers_ErrorEOF(t *testing.T) { require.NoError(t, err) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -554,7 +550,6 @@ func TestRouter_AcceptPeers_HeadOfLineBlocking(t *testing.T) { require.NoError(t, err) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -658,7 +653,6 @@ func TestRouter_DialPeers(t *testing.T) { sub := peerManager.Subscribe(ctx) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -744,7 +738,6 @@ func TestRouter_DialPeers_Parallel(t *testing.T) { require.True(t, added) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -819,7 +812,6 @@ func TestRouter_EvictPeers(t *testing.T) { sub := peerManager.Subscribe(ctx) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -882,7 +874,6 @@ func TestRouter_ChannelCompatability(t *testing.T) { require.NoError(t, err) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, @@ -938,7 +929,6 @@ func TestRouter_DontSendOnInvalidChannel(t *testing.T) { sub := peerManager.Subscribe(ctx) router, err := p2p.NewRouter( - ctx, log.NewNopLogger(), p2p.NopMetrics(), selfInfo, diff --git a/internal/statesync/reactor.go b/internal/statesync/reactor.go index dba520a1c..15abf3ef0 100644 --- a/internal/statesync/reactor.go +++ b/internal/statesync/reactor.go @@ -16,7 +16,6 @@ import ( "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/p2p" - "github.com/tendermint/tendermint/internal/p2p/conn" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/store" "github.com/tendermint/tendermint/libs/log" @@ -139,13 +138,11 @@ type Reactor struct { stateStore sm.Store blockStore *store.BlockStore - conn abciclient.Client - tempDir string - snapshotCh *p2p.Channel - chunkCh *p2p.Channel - blockCh *p2p.Channel - paramsCh *p2p.Channel - peerUpdates *p2p.PeerUpdates + conn abciclient.Client + tempDir string + peerEvents p2p.PeerEventSubscriber + chCreator p2p.ChannelCreator + sendBlockError func(context.Context, p2p.PeerError) error // Dispatcher is used to multiplex light block requests and responses over multiple // peers used by the p2p state provider and in reverse sync. @@ -155,10 +152,13 @@ type Reactor struct { // These will only be set when a state sync is in progress. It is used to feed // received snapshots and chunks into the syncer and manage incoming and outgoing // providers. - mtx sync.RWMutex - syncer *syncer - providers map[types.NodeID]*BlockProvider - stateProvider StateProvider + mtx sync.RWMutex + initSyncer func() *syncer + requestSnaphot func() error + syncer *syncer + providers map[types.NodeID]*BlockProvider + initStateProvider func(ctx context.Context, chainID string, initialHeight int64) error + stateProvider StateProvider eventBus *eventbus.EventBus metrics *Metrics @@ -178,32 +178,13 @@ func NewReactor( logger log.Logger, conn abciclient.Client, channelCreator p2p.ChannelCreator, - peerUpdates *p2p.PeerUpdates, + peerEvents p2p.PeerEventSubscriber, stateStore sm.Store, blockStore *store.BlockStore, tempDir string, ssMetrics *Metrics, eventBus *eventbus.EventBus, -) (*Reactor, error) { - - chDesc := getChannelDescriptors() - - snapshotCh, err := channelCreator(ctx, chDesc[SnapshotChannel]) - if err != nil { - return nil, err - } - chunkCh, err := channelCreator(ctx, chDesc[ChunkChannel]) - if err != nil { - return nil, err - } - blockCh, err := channelCreator(ctx, chDesc[LightBlockChannel]) - if err != nil { - return nil, err - } - paramsCh, err := channelCreator(ctx, chDesc[ParamsChannel]) - if err != nil { - return nil, err - } +) *Reactor { r := &Reactor{ logger: logger, @@ -211,23 +192,19 @@ func NewReactor( initialHeight: initialHeight, cfg: cfg, conn: conn, - snapshotCh: snapshotCh, - chunkCh: chunkCh, - blockCh: blockCh, - paramsCh: paramsCh, - peerUpdates: peerUpdates, + chCreator: channelCreator, + peerEvents: peerEvents, tempDir: tempDir, stateStore: stateStore, blockStore: blockStore, peers: newPeerList(), - dispatcher: NewDispatcher(blockCh), providers: make(map[types.NodeID]*BlockProvider), metrics: ssMetrics, eventBus: eventBus, } r.BaseService = *service.NewBaseService(logger, "StateSync", r) - return r, nil + return r } // OnStart starts separate go routines for each p2p Channel and listens for @@ -237,8 +214,91 @@ func NewReactor( // The caller must be sure to execute OnStop to ensure the outbound p2p Channels are // closed. No error is returned. func (r *Reactor) OnStart(ctx context.Context) error { - go r.processChannels(ctx, r.snapshotCh, r.chunkCh, r.blockCh, r.paramsCh) - go r.processPeerUpdates(ctx) + // construct channels + chDesc := getChannelDescriptors() + snapshotCh, err := r.chCreator(ctx, chDesc[SnapshotChannel]) + if err != nil { + return err + } + chunkCh, err := r.chCreator(ctx, chDesc[ChunkChannel]) + if err != nil { + return err + } + blockCh, err := r.chCreator(ctx, chDesc[LightBlockChannel]) + if err != nil { + return err + } + paramsCh, err := r.chCreator(ctx, chDesc[ParamsChannel]) + if err != nil { + return err + } + + // define constructor and helper functions, that hold + // references to these channels for use later. This is not + // ideal. + r.initSyncer = func() *syncer { + return &syncer{ + logger: r.logger, + stateProvider: r.stateProvider, + conn: r.conn, + snapshots: newSnapshotPool(), + snapshotCh: snapshotCh, + chunkCh: chunkCh, + tempDir: r.tempDir, + fetchers: r.cfg.Fetchers, + retryTimeout: r.cfg.ChunkRequestTimeout, + metrics: r.metrics, + } + } + r.dispatcher = NewDispatcher(blockCh) + r.requestSnaphot = func() error { + // request snapshots from all currently connected peers + return snapshotCh.Send(ctx, p2p.Envelope{ + Broadcast: true, + Message: &ssproto.SnapshotsRequest{}, + }) + } + r.sendBlockError = blockCh.SendError + + r.initStateProvider = func(ctx context.Context, chainID string, initialHeight int64) error { + to := light.TrustOptions{ + Period: r.cfg.TrustPeriod, + Height: r.cfg.TrustHeight, + Hash: r.cfg.TrustHashBytes(), + } + spLogger := r.logger.With("module", "stateprovider") + spLogger.Info("initializing state provider", "trustPeriod", to.Period, + "trustHeight", to.Height, "useP2P", r.cfg.UseP2P) + + if r.cfg.UseP2P { + if err := r.waitForEnoughPeers(ctx, 2); err != nil { + return err + } + + peers := r.peers.All() + providers := make([]provider.Provider, len(peers)) + for idx, p := range peers { + providers[idx] = NewBlockProvider(p, chainID, r.dispatcher) + } + + stateProvider, err := NewP2PStateProvider(ctx, chainID, initialHeight, providers, to, paramsCh, r.logger.With("module", "stateprovider")) + if err != nil { + return fmt.Errorf("failed to initialize P2P state provider: %w", err) + } + r.stateProvider = stateProvider + return nil + } + + stateProvider, err := NewRPCStateProvider(ctx, chainID, initialHeight, r.cfg.RPCServers, to, spLogger) + if err != nil { + return fmt.Errorf("failed to initialize RPC state provider: %w", err) + } + r.stateProvider = stateProvider + return nil + } + + go r.processChannels(ctx, snapshotCh, chunkCh, blockCh, paramsCh) + go r.processPeerUpdates(ctx, r.peerEvents(ctx)) return nil } @@ -281,16 +341,7 @@ func (r *Reactor) Sync(ctx context.Context) (sm.State, error) { return sm.State{}, err } - r.syncer = newSyncer( - r.cfg, - r.logger, - r.conn, - r.stateProvider, - r.snapshotCh, - r.chunkCh, - r.tempDir, - r.metrics, - ) + r.syncer = r.initSyncer() r.mtx.Unlock() defer func() { @@ -301,15 +352,7 @@ func (r *Reactor) Sync(ctx context.Context) (sm.State, error) { r.mtx.Unlock() }() - requestSnapshotsHook := func() error { - // request snapshots from all currently connected peers - return r.snapshotCh.Send(ctx, p2p.Envelope{ - Broadcast: true, - Message: &ssproto.SnapshotsRequest{}, - }) - } - - state, commit, err := r.syncer.SyncAny(ctx, r.cfg.DiscoveryTime, requestSnapshotsHook) + state, commit, err := r.syncer.SyncAny(ctx, r.cfg.DiscoveryTime, r.requestSnaphot) if err != nil { return sm.State{}, err } @@ -436,7 +479,7 @@ func (r *Reactor) backfill( r.logger.Info("backfill: fetched light block failed validate basic, removing peer...", "err", err, "height", height) queue.retry(height) - if serr := r.blockCh.SendError(ctx, p2p.PeerError{ + if serr := r.sendBlockError(ctx, p2p.PeerError{ NodeID: peer, Err: fmt.Errorf("received invalid light block: %w", err), }); serr != nil { @@ -473,7 +516,7 @@ func (r *Reactor) backfill( if w, g := trustedBlockID.Hash, resp.block.Hash(); !bytes.Equal(w, g) { r.logger.Info("received invalid light block. header hash doesn't match trusted LastBlockID", "trustedHash", w, "receivedHash", g, "height", resp.block.Height) - if err := r.blockCh.SendError(ctx, p2p.PeerError{ + if err := r.sendBlockError(ctx, p2p.PeerError{ NodeID: resp.peer, Err: fmt.Errorf("received invalid light block. Expected hash %v, got: %v", w, g), }); err != nil { @@ -534,7 +577,7 @@ func (r *Reactor) backfill( // handleSnapshotMessage handles envelopes sent from peers on the // SnapshotChannel. It returns an error only if the Envelope.Message is unknown // for this channel. This should never be called outside of handleMessage. -func (r *Reactor) handleSnapshotMessage(ctx context.Context, envelope *p2p.Envelope) error { +func (r *Reactor) handleSnapshotMessage(ctx context.Context, envelope *p2p.Envelope, snapshotCh *p2p.Channel) error { logger := r.logger.With("peer", envelope.From) switch msg := envelope.Message.(type) { @@ -553,7 +596,7 @@ func (r *Reactor) handleSnapshotMessage(ctx context.Context, envelope *p2p.Envel "peer", envelope.From, ) - if err := r.snapshotCh.Send(ctx, p2p.Envelope{ + if err := snapshotCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: &ssproto.SnapshotsResponse{ Height: snapshot.Height, @@ -589,8 +632,8 @@ func (r *Reactor) handleSnapshotMessage(ctx context.Context, envelope *p2p.Envel "failed to add snapshot", "height", msg.Height, "format", msg.Format, + "channel", snapshotCh.ID, "err", err, - "channel", r.snapshotCh.ID, ) return nil } @@ -606,7 +649,7 @@ func (r *Reactor) handleSnapshotMessage(ctx context.Context, envelope *p2p.Envel // handleChunkMessage handles envelopes sent from peers on the ChunkChannel. // It returns an error only if the Envelope.Message is unknown for this channel. // This should never be called outside of handleMessage. -func (r *Reactor) handleChunkMessage(ctx context.Context, envelope *p2p.Envelope) error { +func (r *Reactor) handleChunkMessage(ctx context.Context, envelope *p2p.Envelope, chunkCh *p2p.Channel) error { switch msg := envelope.Message.(type) { case *ssproto.ChunkRequest: r.logger.Debug( @@ -640,7 +683,7 @@ func (r *Reactor) handleChunkMessage(ctx context.Context, envelope *p2p.Envelope "chunk", msg.Index, "peer", envelope.From, ) - if err := r.chunkCh.Send(ctx, p2p.Envelope{ + if err := chunkCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: &ssproto.ChunkResponse{ Height: msg.Height, @@ -695,7 +738,7 @@ func (r *Reactor) handleChunkMessage(ctx context.Context, envelope *p2p.Envelope return nil } -func (r *Reactor) handleLightBlockMessage(ctx context.Context, envelope *p2p.Envelope) error { +func (r *Reactor) handleLightBlockMessage(ctx context.Context, envelope *p2p.Envelope, blockCh *p2p.Channel) error { switch msg := envelope.Message.(type) { case *ssproto.LightBlockRequest: r.logger.Info("received light block request", "height", msg.Height) @@ -705,7 +748,7 @@ func (r *Reactor) handleLightBlockMessage(ctx context.Context, envelope *p2p.Env return err } if lb == nil { - if err := r.blockCh.Send(ctx, p2p.Envelope{ + if err := blockCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: &ssproto.LightBlockResponse{ LightBlock: nil, @@ -724,7 +767,7 @@ func (r *Reactor) handleLightBlockMessage(ctx context.Context, envelope *p2p.Env // NOTE: If we don't have the light block we will send a nil light block // back to the requested node, indicating that we don't have it. - if err := r.blockCh.Send(ctx, p2p.Envelope{ + if err := blockCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: &ssproto.LightBlockResponse{ LightBlock: lbproto, @@ -752,7 +795,7 @@ func (r *Reactor) handleLightBlockMessage(ctx context.Context, envelope *p2p.Env return nil } -func (r *Reactor) handleParamsMessage(ctx context.Context, envelope *p2p.Envelope) error { +func (r *Reactor) handleParamsMessage(ctx context.Context, envelope *p2p.Envelope, paramsCh *p2p.Channel) error { switch msg := envelope.Message.(type) { case *ssproto.ParamsRequest: r.logger.Debug("received consensus params request", "height", msg.Height) @@ -763,7 +806,7 @@ func (r *Reactor) handleParamsMessage(ctx context.Context, envelope *p2p.Envelop } cpproto := cp.ToProto() - if err := r.paramsCh.Send(ctx, p2p.Envelope{ + if err := paramsCh.Send(ctx, p2p.Envelope{ To: envelope.From, Message: &ssproto.ParamsResponse{ Height: msg.Height, @@ -801,7 +844,7 @@ func (r *Reactor) handleParamsMessage(ctx context.Context, envelope *p2p.Envelop // handleMessage handles an Envelope sent from a peer on a specific p2p Channel. // It will handle errors and any possible panics gracefully. A caller can handle // any error returned by sending a PeerError on the respective channel. -func (r *Reactor) handleMessage(ctx context.Context, envelope *p2p.Envelope) (err error) { +func (r *Reactor) handleMessage(ctx context.Context, envelope *p2p.Envelope, chans map[p2p.ChannelID]*p2p.Channel) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("panic in processing message: %v", e) @@ -817,13 +860,13 @@ func (r *Reactor) handleMessage(ctx context.Context, envelope *p2p.Envelope) (er switch envelope.ChannelID { case SnapshotChannel: - err = r.handleSnapshotMessage(ctx, envelope) + err = r.handleSnapshotMessage(ctx, envelope, chans[SnapshotChannel]) case ChunkChannel: - err = r.handleChunkMessage(ctx, envelope) + err = r.handleChunkMessage(ctx, envelope, chans[ChunkChannel]) case LightBlockChannel: - err = r.handleLightBlockMessage(ctx, envelope) + err = r.handleLightBlockMessage(ctx, envelope, chans[LightBlockChannel]) case ParamsChannel: - err = r.handleParamsMessage(ctx, envelope) + err = r.handleParamsMessage(ctx, envelope, chans[ParamsChannel]) default: err = fmt.Errorf("unknown channel ID (%d) for envelope (%v)", envelope.ChannelID, envelope) } @@ -840,7 +883,7 @@ func (r *Reactor) processChannels(ctx context.Context, chs ...*p2p.Channel) { ctx, cancel := context.WithCancel(ctx) defer cancel() - chanTable := make(map[conn.ChannelID]*p2p.Channel, len(chs)) + chanTable := make(map[p2p.ChannelID]*p2p.Channel, len(chs)) for idx := range chs { ch := chs[idx] chanTable[ch.ID] = ch @@ -849,7 +892,7 @@ func (r *Reactor) processChannels(ctx context.Context, chs ...*p2p.Channel) { iter := p2p.MergedChannelIterator(ctx, chs...) for iter.Next(ctx) { envelope := iter.Envelope() - if err := r.handleMessage(ctx, envelope); err != nil { + if err := r.handleMessage(ctx, envelope, chanTable); err != nil { ch, ok := chanTable[envelope.ChannelID] if !ok { r.logger.Error("received impossible message", @@ -930,12 +973,12 @@ func (r *Reactor) processPeerUpdate(ctx context.Context, peerUpdate p2p.PeerUpda // processPeerUpdates initiates a blocking process where we listen for and handle // PeerUpdate messages. When the reactor is stopped, we will catch the signal and // close the p2p PeerUpdatesCh gracefully. -func (r *Reactor) processPeerUpdates(ctx context.Context) { +func (r *Reactor) processPeerUpdates(ctx context.Context, peerUpdates *p2p.PeerUpdates) { for { select { case <-ctx.Done(): return - case peerUpdate := <-r.peerUpdates.Updates(): + case peerUpdate := <-peerUpdates.Updates(): r.processPeerUpdate(ctx, peerUpdate) } } @@ -1040,41 +1083,6 @@ func (r *Reactor) waitForEnoughPeers(ctx context.Context, numPeers int) error { return nil } -func (r *Reactor) initStateProvider(ctx context.Context, chainID string, initialHeight int64) error { - var err error - to := light.TrustOptions{ - Period: r.cfg.TrustPeriod, - Height: r.cfg.TrustHeight, - Hash: r.cfg.TrustHashBytes(), - } - spLogger := r.logger.With("module", "stateprovider") - spLogger.Info("initializing state provider", "trustPeriod", to.Period, - "trustHeight", to.Height, "useP2P", r.cfg.UseP2P) - - if r.cfg.UseP2P { - if err := r.waitForEnoughPeers(ctx, 2); err != nil { - return err - } - - peers := r.peers.All() - providers := make([]provider.Provider, len(peers)) - for idx, p := range peers { - providers[idx] = NewBlockProvider(p, chainID, r.dispatcher) - } - - r.stateProvider, err = NewP2PStateProvider(ctx, chainID, initialHeight, providers, to, r.paramsCh, spLogger) - if err != nil { - return fmt.Errorf("failed to initialize P2P state provider: %w", err) - } - } else { - r.stateProvider, err = NewRPCStateProvider(ctx, chainID, initialHeight, r.cfg.RPCServers, to, spLogger) - if err != nil { - return fmt.Errorf("failed to initialize RPC state provider: %w", err) - } - } - return nil -} - func (r *Reactor) TotalSnapshots() int64 { r.mtx.RLock() defer r.mtx.RUnlock() diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index 709fe9a2c..f59a6e4ee 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -154,8 +154,7 @@ func setup( logger := log.NewNopLogger() - var err error - rts.reactor, err = NewReactor( + rts.reactor = NewReactor( ctx, factory.DefaultTestChainID, 1, @@ -163,25 +162,26 @@ func setup( logger.With("component", "reactor"), conn, chCreator, - rts.peerUpdates, + func(context.Context) *p2p.PeerUpdates { return rts.peerUpdates }, rts.stateStore, rts.blockStore, "", m, nil, // eventbus can be nil ) - require.NoError(t, err) - rts.syncer = newSyncer( - *cfg, - logger.With("component", "syncer"), - conn, - stateProvider, - rts.snapshotChannel, - rts.chunkChannel, - "", - rts.reactor.metrics, - ) + rts.syncer = &syncer{ + logger: logger, + stateProvider: stateProvider, + conn: conn, + snapshots: newSnapshotPool(), + snapshotCh: rts.snapshotChannel, + chunkCh: rts.chunkChannel, + tempDir: t.TempDir(), + fetchers: cfg.Fetchers, + retryTimeout: cfg.ChunkRequestTimeout, + metrics: rts.reactor.metrics, + } ctx, cancel := context.WithCancel(ctx) diff --git a/internal/statesync/syncer.go b/internal/statesync/syncer.go index 78eb8d53a..c2cca9a7c 100644 --- a/internal/statesync/syncer.go +++ b/internal/statesync/syncer.go @@ -10,7 +10,6 @@ import ( abciclient "github.com/tendermint/tendermint/abci/client" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/p2p" "github.com/tendermint/tendermint/internal/proxy" sm "github.com/tendermint/tendermint/internal/state" @@ -72,31 +71,6 @@ type syncer struct { processingSnapshot *snapshot } -// newSyncer creates a new syncer. -func newSyncer( - cfg config.StateSyncConfig, - logger log.Logger, - conn abciclient.Client, - stateProvider StateProvider, - snapshotCh *p2p.Channel, - chunkCh *p2p.Channel, - tempDir string, - metrics *Metrics, -) *syncer { - return &syncer{ - logger: logger, - stateProvider: stateProvider, - conn: conn, - snapshots: newSnapshotPool(), - snapshotCh: snapshotCh, - chunkCh: chunkCh, - tempDir: tempDir, - fetchers: cfg.Fetchers, - retryTimeout: cfg.ChunkRequestTimeout, - metrics: metrics, - } -} - // AddChunk adds a chunk to the chunk queue, if any. It returns false if the chunk has already // been added to the queue, or an error if there's no sync in progress. func (s *syncer) AddChunk(chunk *chunk) (bool, error) { diff --git a/node/node.go b/node/node.go index 34350e09f..7c3ca1268 100644 --- a/node/node.go +++ b/node/node.go @@ -88,12 +88,11 @@ func newDefaultNode( } if cfg.Mode == config.ModeSeed { return makeSeedNode( - ctx, + logger, cfg, config.DefaultDBProvider, nodeKey, defaultGenesisDocProviderFunc(cfg), - logger, ) } pval, err := makeDefaultPrivval(cfg) @@ -244,7 +243,7 @@ func makeNode( // TODO: Fetch and provide real options and do proper p2p bootstrapping. // TODO: Use a persistent peer database. - nodeInfo, err := makeNodeInfo(cfg, nodeKey, eventSinks, genDoc, state) + nodeInfo, err := makeNodeInfo(cfg, nodeKey, eventSinks, genDoc, state.Version.Consensus) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) } @@ -257,24 +256,21 @@ func makeNode( makeCloser(closers)) } - router, err := createRouter(ctx, logger, nodeMetrics.p2p, nodeInfo, nodeKey, - peerManager, cfg, proxyApp) + router, err := createRouter(logger, nodeMetrics.p2p, nodeInfo, nodeKey, peerManager, cfg, proxyApp) if err != nil { return nil, combineCloseError( fmt.Errorf("failed to create router: %w", err), makeCloser(closers)) } - mpReactor, mp, err := createMempoolReactor(ctx, - cfg, proxyApp, stateStore, nodeMetrics.mempool, peerManager, router, logger, - ) + mpReactor, mp, err := createMempoolReactor(logger, cfg, proxyApp, stateStore, nodeMetrics.mempool, + peerManager.Subscribe, router.OpenChannel, peerManager.GetHeight) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) } - evReactor, evPool, edbCloser, err := createEvidenceReactor(ctx, - cfg, dbProvider, stateStore, blockStore, peerManager, router, logger, nodeMetrics.evidence, eventBus, - ) + evReactor, evPool, edbCloser, err := createEvidenceReactor(logger, cfg, dbProvider, + stateStore, blockStore, peerManager.Subscribe, router.OpenChannel, nodeMetrics.evidence, eventBus) closers = append(closers, edbCloser) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) @@ -295,11 +291,12 @@ func makeNode( // Determine whether we should do block sync. This must happen after the handshake, since the // app may modify the validator set, specifying ourself as the only validator. blockSync := !onlyValidatorIsUs(state, pubKey) + waitSync := stateSync || blockSync csReactor, csState, err := createConsensusReactor(ctx, cfg, stateStore, blockExec, blockStore, mp, evPool, - privValidator, nodeMetrics.consensus, stateSync || blockSync, eventBus, - peerManager, router, logger, + privValidator, nodeMetrics.consensus, waitSync, eventBus, + peerManager, router.OpenChannel, logger, ) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) @@ -307,23 +304,18 @@ func makeNode( // Create the blockchain reactor. Note, we do not start block sync if we're // doing a state sync first. - bcReactor, err := blocksync.NewReactor(ctx, + bcReactor := blocksync.NewReactor( logger.With("module", "blockchain"), stateStore, blockExec, blockStore, csReactor, router.OpenChannel, - peerManager.Subscribe(ctx), + peerManager.Subscribe, blockSync && !stateSync, nodeMetrics.consensus, eventBus, ) - if err != nil { - return nil, combineCloseError( - fmt.Errorf("could not create blocksync reactor: %w", err), - makeCloser(closers)) - } // Make ConsensusReactor. Don't enable fully if doing a state sync and/or block sync first. // FIXME We need to update metrics here, since other reactors don't have access to them. @@ -337,7 +329,7 @@ func makeNode( // FIXME The way we do phased startups (e.g. replay -> block sync -> consensus) is very messy, // we should clean this whole thing up. See: // https://github.com/tendermint/tendermint/issues/4644 - stateSyncReactor, err := statesync.NewReactor( + stateSyncReactor := statesync.NewReactor( ctx, genDoc.ChainID, genDoc.InitialHeight, @@ -345,23 +337,17 @@ func makeNode( logger.With("module", "statesync"), proxyApp, router.OpenChannel, - peerManager.Subscribe(ctx), + peerManager.Subscribe, stateStore, blockStore, cfg.StateSync.TempDir, nodeMetrics.statesync, eventBus, ) - if err != nil { - return nil, combineCloseError(err, makeCloser(closers)) - } var pexReactor service.Service = service.NopService{} if cfg.P2P.PexReactor { - pexReactor, err = pex.NewReactor(ctx, logger, peerManager, router.OpenChannel, peerManager.Subscribe(ctx)) - if err != nil { - return nil, combineCloseError(err, makeCloser(closers)) - } + pexReactor = pex.NewReactor(logger, peerManager, router.OpenChannel, peerManager.Subscribe) } node := &nodeImpl{ config: cfg, diff --git a/node/node_test.go b/node/node_test.go index a03d7286e..1a1fa6f81 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -581,12 +581,12 @@ func TestNodeNewSeedNode(t *testing.T) { logger := log.NewNopLogger() - ns, err := makeSeedNode(ctx, + ns, err := makeSeedNode( + logger, cfg, config.DefaultDBProvider, nodeKey, defaultGenesisDocProviderFunc(cfg), - logger, ) t.Cleanup(ns.Wait) t.Cleanup(leaktest.CheckTimeout(t, time.Second)) diff --git a/node/public.go b/node/public.go index af3aece8e..db292833e 100644 --- a/node/public.go +++ b/node/public.go @@ -68,7 +68,7 @@ func New( config.DefaultDBProvider, logger) case config.ModeSeed: - return makeSeedNode(ctx, conf, config.DefaultDBProvider, nodeKey, genProvider, logger) + return makeSeedNode(logger, conf, config.DefaultDBProvider, nodeKey, genProvider) default: return nil, fmt.Errorf("%q is not a valid mode", conf.Mode) } diff --git a/node/seed.go b/node/seed.go index 970896cc6..6da7ff05f 100644 --- a/node/seed.go +++ b/node/seed.go @@ -40,12 +40,11 @@ type seedNodeImpl struct { // makeSeedNode returns a new seed node, containing only p2p, pex reactor func makeSeedNode( - ctx context.Context, + logger log.Logger, 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") @@ -76,19 +75,13 @@ func makeSeedNode( closer) } - router, err := createRouter(ctx, logger, p2pMetrics, nodeInfo, nodeKey, - peerManager, cfg, nil) + router, err := createRouter(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, @@ -101,7 +94,7 @@ func makeSeedNode( shutdownOps: closer, - pexReactor: pexReactor, + pexReactor: pex.NewReactor(logger, peerManager, router.OpenChannel, peerManager.Subscribe), } node.BaseService = *service.NewBaseService(logger, "SeedNode", node) diff --git a/node/setup.go b/node/setup.go index 48ffcb073..07626d611 100644 --- a/node/setup.go +++ b/node/setup.go @@ -169,14 +169,14 @@ func onlyValidatorIsUs(state sm.State, pubKey crypto.PubKey) bool { } func createMempoolReactor( - ctx context.Context, + logger log.Logger, cfg *config.Config, appClient abciclient.Client, store sm.Store, memplMetrics *mempool.Metrics, - peerManager *p2p.PeerManager, - router *p2p.Router, - logger log.Logger, + peerEvents p2p.PeerEventSubscriber, + chCreator p2p.ChannelCreator, + peerHeight func(types.NodeID) int64, ) (service.Service, mempool.Mempool, error) { logger = logger.With("module", "mempool") @@ -189,18 +189,14 @@ func createMempoolReactor( mempool.WithPostCheck(sm.TxPostCheckFromStore(store)), ) - reactor, err := mempool.NewReactor( - ctx, + reactor := mempool.NewReactor( logger, cfg.Mempool, - peerManager, mp, - router.OpenChannel, - peerManager.Subscribe(ctx), + chCreator, + peerEvents, + peerHeight, ) - if err != nil { - return nil, nil, err - } if cfg.Consensus.WaitForTxs() { mp.EnableTxsAvailable() @@ -210,14 +206,13 @@ func createMempoolReactor( } func createEvidenceReactor( - ctx context.Context, + logger log.Logger, cfg *config.Config, dbProvider config.DBProvider, store sm.Store, blockStore *store.BlockStore, - peerManager *p2p.PeerManager, - router *p2p.Router, - logger log.Logger, + peerEvents p2p.PeerEventSubscriber, + chCreator p2p.ChannelCreator, metrics *evidence.Metrics, eventBus *eventbus.EventBus, ) (*evidence.Reactor, *evidence.Pool, closer, error) { @@ -231,16 +226,12 @@ func createEvidenceReactor( evidencePool := evidence.NewPool(logger, evidenceDB, store, blockStore, metrics, eventBus) - evidenceReactor, err := evidence.NewReactor( - ctx, + evidenceReactor := evidence.NewReactor( logger, - router.OpenChannel, - peerManager.Subscribe(ctx), + chCreator, + peerEvents, evidencePool, ) - if err != nil { - return nil, nil, dbCloser, fmt.Errorf("creating evidence reactor: %w", err) - } return evidenceReactor, evidencePool, dbCloser, nil } @@ -258,7 +249,7 @@ func createConsensusReactor( waitSync bool, eventBus *eventbus.EventBus, peerManager *p2p.PeerManager, - router *p2p.Router, + chCreator p2p.ChannelCreator, logger log.Logger, ) (*consensus.Reactor, *consensus.State, error) { logger = logger.With("module", "consensus") @@ -282,20 +273,15 @@ func createConsensusReactor( consensusState.SetPrivValidator(ctx, privValidator) } - reactor, err := consensus.NewReactor( - ctx, + reactor := consensus.NewReactor( logger, consensusState, - router.OpenChannel, - peerManager.Subscribe(ctx), + chCreator, + peerManager.Subscribe, eventBus, waitSync, csMetrics, ) - if err != nil { - return nil, nil, err - } - return reactor, consensusState, nil } @@ -375,7 +361,6 @@ func createPeerManager( } func createRouter( - ctx context.Context, logger log.Logger, p2pMetrics *p2p.Metrics, nodeInfo types.NodeInfo, @@ -405,7 +390,6 @@ func createRouter( } return p2p.NewRouter( - ctx, p2pLogger, p2pMetrics, nodeInfo, @@ -422,7 +406,7 @@ func makeNodeInfo( nodeKey types.NodeKey, eventSinks []indexer.EventSink, genDoc *types.GenesisDoc, - state sm.State, + versionInfo version.Consensus, ) (types.NodeInfo, error) { txIndexerStatus := "off" @@ -434,8 +418,8 @@ func makeNodeInfo( nodeInfo := types.NodeInfo{ ProtocolVersion: types.ProtocolVersion{ P2P: version.P2PProtocol, // global - Block: state.Version.Consensus.Block, - App: state.Version.Consensus.App, + Block: versionInfo.Block, + App: versionInfo.App, }, NodeID: nodeKey.ID, Network: genDoc.ChainID, From 0a23b1e51d03643a0e6103e027ae0bf522c47f96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 15:47:24 +0000 Subject: [PATCH 14/20] build(deps): Bump github.com/vektra/mockery/v2 from 2.10.2 to 2.10.4 (#8250) Bumps [github.com/vektra/mockery/v2](https://github.com/vektra/mockery) from 2.10.2 to 2.10.4.
Release notes

Sourced from github.com/vektra/mockery/v2's releases.

v2.10.4

Changelog

  • c943e69 Merge pull request #441 from cfstras/fix/support-more-env-keys
  • ed87cf6 fix: allow configuring flags with "-" as Env var
  • 17abd96 fix: unused config field Tags
  • 53114cf test: add test for env var configurations

v2.10.3

Changelog

  • ee25bcf Add/update mocks
  • 4703d1a Merge pull request #444 from vektra/remove_need_deps
  • ba1f213 Remove packages.NeedDeps
  • ed38b20 Update go.sum
Commits
  • c943e69 Merge pull request #441 from cfstras/fix/support-more-env-keys
  • 4703d1a Merge pull request #444 from vektra/remove_need_deps
  • ed38b20 Update go.sum
  • ee25bcf Add/update mocks
  • ba1f213 Remove packages.NeedDeps
  • 17abd96 fix: unused config field Tags
  • 53114cf test: add test for env var configurations
  • ed87cf6 fix: allow configuring flags with "-" as Env var
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/vektra/mockery/v2&package-manager=go_modules&previous-version=2.10.2&new-version=2.10.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- abci/client/mocks/client.go | 1 - abci/types/mocks/application.go | 1 - go.mod | 2 +- go.sum | 4 ++-- internal/consensus/mocks/cons_sync_reactor.go | 1 - internal/evidence/mocks/block_store.go | 1 - internal/state/indexer/mocks/event_sink.go | 1 - internal/state/mocks/evidence_pool.go | 1 - internal/state/mocks/store.go | 1 - internal/statesync/mocks/state_provider.go | 1 - rpc/client/mocks/client.go | 23 +++++++++++++++++++ 11 files changed, 26 insertions(+), 11 deletions(-) diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index 7743e5897..37df53979 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - types "github.com/tendermint/tendermint/abci/types" ) diff --git a/abci/types/mocks/application.go b/abci/types/mocks/application.go index 45e2f1c45..30bf0f84c 100644 --- a/abci/types/mocks/application.go +++ b/abci/types/mocks/application.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - types "github.com/tendermint/tendermint/abci/types" ) diff --git a/go.mod b/go.mod index 7951b645f..4db965b87 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/creachadair/atomicfile v0.2.4 github.com/golangci/golangci-lint v1.45.2 github.com/google/go-cmp v0.5.7 - github.com/vektra/mockery/v2 v2.10.2 + github.com/vektra/mockery/v2 v2.10.4 gotest.tools v2.2.0+incompatible ) diff --git a/go.sum b/go.sum index 60b4842b6..94fc35977 100644 --- a/go.sum +++ b/go.sum @@ -1035,8 +1035,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vektra/mockery/v2 v2.10.2 h1:ISAFkB3rQS6Y3aDZzAKtDwgeyDknwNa1aBE3Zgx0h+I= -github.com/vektra/mockery/v2 v2.10.2/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4= +github.com/vektra/mockery/v2 v2.10.4 h1:nMdsCKIS7ZdNTRNS/77Bx6Q/UbasGcfc3Nx7JO7HGTg= +github.com/vektra/mockery/v2 v2.10.4/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4= github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= diff --git a/internal/consensus/mocks/cons_sync_reactor.go b/internal/consensus/mocks/cons_sync_reactor.go index b254fc701..5ac592f0d 100644 --- a/internal/consensus/mocks/cons_sync_reactor.go +++ b/internal/consensus/mocks/cons_sync_reactor.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/internal/state" ) diff --git a/internal/evidence/mocks/block_store.go b/internal/evidence/mocks/block_store.go index 5ea8d8344..ef3346b2a 100644 --- a/internal/evidence/mocks/block_store.go +++ b/internal/evidence/mocks/block_store.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - types "github.com/tendermint/tendermint/types" ) diff --git a/internal/state/indexer/mocks/event_sink.go b/internal/state/indexer/mocks/event_sink.go index 6173480dd..d5555a417 100644 --- a/internal/state/indexer/mocks/event_sink.go +++ b/internal/state/indexer/mocks/event_sink.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - indexer "github.com/tendermint/tendermint/internal/state/indexer" query "github.com/tendermint/tendermint/internal/pubsub/query" diff --git a/internal/state/mocks/evidence_pool.go b/internal/state/mocks/evidence_pool.go index b4f42e580..04e8be7bc 100644 --- a/internal/state/mocks/evidence_pool.go +++ b/internal/state/mocks/evidence_pool.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/internal/state" types "github.com/tendermint/tendermint/types" diff --git a/internal/state/mocks/store.go b/internal/state/mocks/store.go index b7a58e415..02c69d3e0 100644 --- a/internal/state/mocks/store.go +++ b/internal/state/mocks/store.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/internal/state" tendermintstate "github.com/tendermint/tendermint/proto/tendermint/state" diff --git a/internal/statesync/mocks/state_provider.go b/internal/statesync/mocks/state_provider.go index b19a6787f..b8d681631 100644 --- a/internal/statesync/mocks/state_provider.go +++ b/internal/statesync/mocks/state_provider.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/internal/state" types "github.com/tendermint/tendermint/types" diff --git a/rpc/client/mocks/client.go b/rpc/client/mocks/client.go index ffa1d1f29..d9049ea44 100644 --- a/rpc/client/mocks/client.go +++ b/rpc/client/mocks/client.go @@ -411,6 +411,29 @@ func (_m *Client) DumpConsensusState(_a0 context.Context) (*coretypes.ResultDump return r0, r1 } +// Events provides a mock function with given fields: ctx, req +func (_m *Client) Events(ctx context.Context, req *coretypes.RequestEvents) (*coretypes.ResultEvents, error) { + ret := _m.Called(ctx, req) + + var r0 *coretypes.ResultEvents + if rf, ok := ret.Get(0).(func(context.Context, *coretypes.RequestEvents) *coretypes.ResultEvents); ok { + r0 = rf(ctx, req) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*coretypes.ResultEvents) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *coretypes.RequestEvents) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Genesis provides a mock function with given fields: _a0 func (_m *Client) Genesis(_a0 context.Context) (*coretypes.ResultGenesis, error) { ret := _m.Called(_a0) From 60f88194ec0907ad546688cf22060a14b7996d39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 16:56:48 +0000 Subject: [PATCH 15/20] build(deps): Bump github.com/BurntSushi/toml from 1.0.0 to 1.1.0 (#8251) Bumps [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml) from 1.0.0 to 1.1.0.
Release notes

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

v1.1.0

Just a few bugfixes:

  • Skip fields with toml:"-" even when they're unsupported types. Previously something like this would fail to encode due to func being an unsupported type:

    struct {
        Str  string `toml:"str"
        Func func() `toml:"-"`
    }
    
  • Multiline strings can't end with \. This is valid:

    # Valid
    key = """ foo \
    """
    

    Invalid

    key = """ foo \ """

  • Don't quote values in TOMLMarshaler. Previously they would always include quoting (e.g. "value"), while the entire point of this interface is to bypass that.

Commits
  • 891d261 Don't error out if a multiline string ends with an incomplete UTF-8 sequence
  • ef65e34 Don't run Unmarshal() through Decode()
  • 573cad4 Merge pull request #347 from zhsj/fix-32
  • f3633f4 Fix test on 32 bit arch
  • 551f4a5 Merge pull request #344 from lucasbutn/hotfix-341-marshaler-shouldnot-writequ...
  • dec5825 Removed write quote in marshal to allow write other types than strings
  • 2249a9c Multiline strings can't end with ""
  • 51b22f2 Fix README
  • 01e5516 Skip fields with toml:"-", even when they're unsupported types
  • 87b9f05 Fix tests for older Go versions
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/BurntSushi/toml&package-manager=go_modules&previous-version=1.0.0&new-version=1.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4db965b87..3b0004ba0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/tendermint/tendermint go 1.17 require ( - github.com/BurntSushi/toml v1.0.0 + github.com/BurntSushi/toml v1.1.0 github.com/adlio/schema v1.3.0 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 94fc35977..7374c90d0 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,9 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2 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 v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= From 2304ea70f7f98cf1759510b24e3a95ddecb45d2a Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 6 Apr 2022 11:07:21 -0400 Subject: [PATCH 16/20] consensus: remove string indented function (#8257) --- internal/consensus/reactor.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index 4bc109515..1c6c99cb9 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -299,22 +299,6 @@ func (r *Reactor) String() string { return "ConsensusReactor" } -// StringIndented returns an indented string representation of the Reactor. -func (r *Reactor) StringIndented(indent string) string { - r.mtx.RLock() - defer r.mtx.RUnlock() - - s := "ConsensusReactor{\n" - s += indent + " " + r.state.StringIndented(indent+" ") + "\n" - - for _, ps := range r.peers { - s += indent + " " + ps.StringIndented(indent+" ") + "\n" - } - - s += indent + "}" - return s -} - // GetPeerState returns PeerState for a given NodeID. func (r *Reactor) GetPeerState(peerID types.NodeID) (*PeerState, bool) { r.mtx.RLock() From d1533884463da76ccee02e1392c63789dff93a83 Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 6 Apr 2022 14:02:07 -0400 Subject: [PATCH 17/20] p2p: inject nodeinfo into router (#8261) --- internal/p2p/p2ptest/network.go | 2 +- internal/p2p/router.go | 32 ++++++++++++++++-------------- internal/p2p/router_init_test.go | 8 ++++---- internal/p2p/router_test.go | 20 +++++++++---------- node/node.go | 34 ++++++++++++++++---------------- node/node_test.go | 2 +- node/seed.go | 4 +--- node/setup.go | 4 ++-- 8 files changed, 53 insertions(+), 53 deletions(-) diff --git a/internal/p2p/p2ptest/network.go b/internal/p2p/p2ptest/network.go index 6016ce0a5..cde14e721 100644 --- a/internal/p2p/p2ptest/network.go +++ b/internal/p2p/p2ptest/network.go @@ -261,9 +261,9 @@ func (n *Network) MakeNode(ctx context.Context, t *testing.T, opts NodeOptions) router, err := p2p.NewRouter( n.logger, p2p.NopMetrics(), - nodeInfo, privKey, peerManager, + func() *types.NodeInfo { return &nodeInfo }, []p2p.Transport{transport}, transport.Endpoints(), p2p.RouterOptions{DialSleep: func(_ context.Context) {}}, diff --git a/internal/p2p/router.go b/internal/p2p/router.go index 025769592..ca9536900 100644 --- a/internal/p2p/router.go +++ b/internal/p2p/router.go @@ -150,7 +150,6 @@ type Router struct { metrics *Metrics options RouterOptions - nodeInfo types.NodeInfo privKey crypto.PrivKey peerManager *PeerManager chDescs []*ChannelDescriptor @@ -162,8 +161,9 @@ type Router struct { peerMtx sync.RWMutex peerQueues map[types.NodeID]queue // outbound messages per peer for all channels // the channels that the peer queue has open - peerChannels map[types.NodeID]ChannelIDSet - queueFactory func(int) queue + peerChannels map[types.NodeID]ChannelIDSet + queueFactory func(int) queue + nodeInfoProducer func() *types.NodeInfo // FIXME: We don't strictly need to use a mutex for this if we seal the // channels on router start. This depends on whether we want to allow @@ -179,9 +179,9 @@ type Router struct { func NewRouter( logger log.Logger, metrics *Metrics, - nodeInfo types.NodeInfo, privKey crypto.PrivKey, peerManager *PeerManager, + nodeInfoProducer func() *types.NodeInfo, transports []Transport, endpoints []Endpoint, options RouterOptions, @@ -192,10 +192,10 @@ func NewRouter( } router := &Router{ - logger: logger, - metrics: metrics, - nodeInfo: nodeInfo, - privKey: privKey, + logger: logger, + metrics: metrics, + privKey: privKey, + nodeInfoProducer: nodeInfoProducer, connTracker: newConnTracker( options.MaxIncomingConnectionAttempts, options.IncomingConnectionWindow, @@ -284,7 +284,7 @@ func (r *Router) OpenChannel(ctx context.Context, chDesc *ChannelDescriptor) (*C r.channelMessages[id] = messageType // add the channel to the nodeInfo if it's not already there. - r.nodeInfo.AddChannel(uint16(chDesc.ID)) + r.nodeInfoProducer().AddChannel(uint16(chDesc.ID)) for _, t := range r.transports { t.AddChannelDescriptors([]*ChannelDescriptor{chDesc}) @@ -715,7 +715,8 @@ func (r *Router) handshakePeer( defer cancel() } - peerInfo, peerKey, err := conn.Handshake(ctx, r.nodeInfo, r.privKey) + nodeInfo := r.nodeInfoProducer() + peerInfo, peerKey, err := conn.Handshake(ctx, *nodeInfo, r.privKey) if err != nil { return peerInfo, err } @@ -730,7 +731,7 @@ func (r *Router) handshakePeer( return peerInfo, fmt.Errorf("expected to connect with peer %q, got %q", expectID, peerInfo.NodeID) } - if err := r.nodeInfo.CompatibleWith(peerInfo); err != nil { + if err := r.nodeInfoProducer().CompatibleWith(peerInfo); err != nil { return peerInfo, ErrRejected{ err: err, id: peerInfo.ID(), @@ -930,7 +931,7 @@ func (r *Router) evictPeers(ctx context.Context) { // NodeInfo returns a copy of the current NodeInfo. Used for testing. func (r *Router) NodeInfo() types.NodeInfo { - return r.nodeInfo.Copy() + return r.nodeInfoProducer().Copy() } func (r *Router) setupQueueFactory(ctx context.Context) error { @@ -957,11 +958,12 @@ func (r *Router) OnStart(ctx context.Context) error { } } + nodeInfo := r.nodeInfoProducer() r.logger.Info( "starting router", - "node_id", r.nodeInfo.NodeID, - "channels", r.nodeInfo.Channels, - "listen_addr", r.nodeInfo.ListenAddr, + "node_id", nodeInfo.NodeID, + "channels", nodeInfo.Channels, + "listen_addr", nodeInfo.ListenAddr, "transports", len(r.transports), ) diff --git a/internal/p2p/router_init_test.go b/internal/p2p/router_init_test.go index d58c79487..20c3cb6dc 100644 --- a/internal/p2p/router_init_test.go +++ b/internal/p2p/router_init_test.go @@ -23,7 +23,7 @@ func TestRouter_ConstructQueueFactory(t *testing.T) { t.Run("Default", func(t *testing.T) { require.Zero(t, os.Getenv("TM_P2P_QUEUE")) opts := RouterOptions{} - r, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + r, err := NewRouter(log.NewNopLogger(), nil, nil, nil, func() *types.NodeInfo { return &types.NodeInfo{} }, nil, nil, opts) require.NoError(t, err) require.NoError(t, r.setupQueueFactory(ctx)) @@ -32,7 +32,7 @@ func TestRouter_ConstructQueueFactory(t *testing.T) { }) t.Run("Fifo", func(t *testing.T) { opts := RouterOptions{QueueType: queueTypeFifo} - r, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + r, err := NewRouter(log.NewNopLogger(), nil, nil, nil, func() *types.NodeInfo { return &types.NodeInfo{} }, nil, nil, opts) require.NoError(t, err) require.NoError(t, r.setupQueueFactory(ctx)) @@ -41,7 +41,7 @@ func TestRouter_ConstructQueueFactory(t *testing.T) { }) t.Run("Priority", func(t *testing.T) { opts := RouterOptions{QueueType: queueTypePriority} - r, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + r, err := NewRouter(log.NewNopLogger(), nil, nil, nil, func() *types.NodeInfo { return &types.NodeInfo{} }, nil, nil, opts) require.NoError(t, err) require.NoError(t, r.setupQueueFactory(ctx)) @@ -51,7 +51,7 @@ func TestRouter_ConstructQueueFactory(t *testing.T) { }) t.Run("NonExistant", func(t *testing.T) { opts := RouterOptions{QueueType: "fast"} - _, err := NewRouter(log.NewNopLogger(), nil, types.NodeInfo{}, nil, nil, nil, nil, opts) + _, err := NewRouter(log.NewNopLogger(), nil, nil, nil, func() *types.NodeInfo { return &types.NodeInfo{} }, nil, nil, opts) require.Error(t, err) require.Contains(t, err.Error(), "fast") }) diff --git a/internal/p2p/router_test.go b/internal/p2p/router_test.go index 5facfdaff..7ef77a16d 100644 --- a/internal/p2p/router_test.go +++ b/internal/p2p/router_test.go @@ -108,9 +108,9 @@ func TestRouter_Channel_Basic(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, nil, nil, p2p.RouterOptions{}, @@ -410,9 +410,9 @@ func TestRouter_AcceptPeers(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -464,9 +464,9 @@ func TestRouter_AcceptPeers_Error(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -501,9 +501,9 @@ func TestRouter_AcceptPeers_ErrorEOF(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -552,9 +552,9 @@ func TestRouter_AcceptPeers_HeadOfLineBlocking(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -655,9 +655,9 @@ func TestRouter_DialPeers(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -740,9 +740,9 @@ func TestRouter_DialPeers_Parallel(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{ @@ -814,9 +814,9 @@ func TestRouter_EvictPeers(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -876,9 +876,9 @@ func TestRouter_ChannelCompatability(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, @@ -931,9 +931,9 @@ func TestRouter_DontSendOnInvalidChannel(t *testing.T) { router, err := p2p.NewRouter( log.NewNopLogger(), p2p.NopMetrics(), - selfInfo, selfKey, peerManager, + func() *types.NodeInfo { return &selfInfo }, []p2p.Transport{mockTransport}, nil, p2p.RouterOptions{}, diff --git a/node/node.go b/node/node.go index 7c3ca1268..e1f4205ad 100644 --- a/node/node.go +++ b/node/node.go @@ -54,10 +54,10 @@ type nodeImpl struct { privValidator types.PrivValidator // local node's validator key // network - peerManager *p2p.PeerManager - router *p2p.Router - nodeInfo types.NodeInfo - nodeKey types.NodeKey // our node privkey + peerManager *p2p.PeerManager + router *p2p.Router + nodeInfoProducer func() *types.NodeInfo + nodeKey types.NodeKey // our node privkey // services eventSinks []indexer.EventSink @@ -213,13 +213,6 @@ func makeNode( } } - // Determine whether we should attempt state sync. - stateSync := cfg.StateSync.Enable && !onlyValidatorIsUs(state, pubKey) - if stateSync && state.LastBlockHeight > 0 { - logger.Info("Found local state with non-zero height, skipping state sync") - stateSync = false - } - // Create the handshaker, which calls RequestInfo, sets the AppVersion on the state, // and replays any blocks as necessary to sync tendermint with the app. if err := consensus.NewHandshaker( @@ -256,7 +249,7 @@ func makeNode( makeCloser(closers)) } - router, err := createRouter(logger, nodeMetrics.p2p, nodeInfo, nodeKey, peerManager, cfg, proxyApp) + router, err := createRouter(logger, nodeMetrics.p2p, func() *types.NodeInfo { return &nodeInfo }, nodeKey, peerManager, cfg, proxyApp) if err != nil { return nil, combineCloseError( fmt.Errorf("failed to create router: %w", err), @@ -288,6 +281,13 @@ func makeNode( nodeMetrics.state, ) + // Determine whether we should attempt state sync. + stateSync := cfg.StateSync.Enable && !onlyValidatorIsUs(state, pubKey) + if stateSync && state.LastBlockHeight > 0 { + logger.Info("Found local state with non-zero height, skipping state sync") + stateSync = false + } + // Determine whether we should do block sync. This must happen after the handshake, since the // app may modify the validator set, specifying ourself as the only validator. blockSync := !onlyValidatorIsUs(state, pubKey) @@ -355,10 +355,10 @@ func makeNode( genesisDoc: genDoc, privValidator: privValidator, - peerManager: peerManager, - router: router, - nodeInfo: nodeInfo, - nodeKey: nodeKey, + peerManager: peerManager, + router: router, + nodeInfoProducer: func() *types.NodeInfo { return &nodeInfo }, + nodeKey: nodeKey, eventSinks: eventSinks, @@ -458,7 +458,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { return err } - n.rpcEnv.NodeInfo = n.nodeInfo + n.rpcEnv.NodeInfo = n.nodeInfoProducer().Copy() // Start the RPC server before the P2P server // so we can eg. receive txs for the first block if n.config.RPC.ListenAddress != "" { diff --git a/node/node_test.go b/node/node_test.go index 1a1fa6f81..86ed7960c 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -147,7 +147,7 @@ func TestNodeSetAppVersion(t *testing.T) { assert.Equal(t, state.Version.Consensus.App, appVersion) // check version is set in node info - assert.Equal(t, n.nodeInfo.ProtocolVersion.App, appVersion) + assert.Equal(t, n.nodeInfoProducer().ProtocolVersion.App, appVersion) } func TestNodeSetPrivValTCP(t *testing.T) { diff --git a/node/seed.go b/node/seed.go index 6da7ff05f..a0b71e411 100644 --- a/node/seed.go +++ b/node/seed.go @@ -29,7 +29,6 @@ type seedNodeImpl struct { // network peerManager *p2p.PeerManager router *p2p.Router - nodeInfo types.NodeInfo nodeKey types.NodeKey // our node privkey isListening bool @@ -75,7 +74,7 @@ func makeSeedNode( closer) } - router, err := createRouter(logger, p2pMetrics, nodeInfo, nodeKey, peerManager, cfg, nil) + router, err := createRouter(logger, p2pMetrics, func() *types.NodeInfo { return &nodeInfo }, nodeKey, peerManager, cfg, nil) if err != nil { return nil, combineCloseError( fmt.Errorf("failed to create router: %w", err), @@ -87,7 +86,6 @@ func makeSeedNode( logger: logger, genesisDoc: genDoc, - nodeInfo: nodeInfo, nodeKey: nodeKey, peerManager: peerManager, router: router, diff --git a/node/setup.go b/node/setup.go index 07626d611..e87fac79c 100644 --- a/node/setup.go +++ b/node/setup.go @@ -363,7 +363,7 @@ func createPeerManager( func createRouter( logger log.Logger, p2pMetrics *p2p.Metrics, - nodeInfo types.NodeInfo, + nodeInfoProducer func() *types.NodeInfo, nodeKey types.NodeKey, peerManager *p2p.PeerManager, cfg *config.Config, @@ -392,9 +392,9 @@ func createRouter( return p2p.NewRouter( p2pLogger, p2pMetrics, - nodeInfo, nodeKey.PrivKey, peerManager, + nodeInfoProducer, []p2p.Transport{transport}, []p2p.Endpoint{ep}, getRouterConfig(cfg, appClient), From 85364a9ba87e1fcd8fcaed71ad2c98983e3702ce Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 6 Apr 2022 14:59:30 -0400 Subject: [PATCH 18/20] node: reorder service construction (#8262) --- node/node.go | 141 +++++++++++++++++++++++----------------------- node/node_test.go | 2 +- 2 files changed, 71 insertions(+), 72 deletions(-) diff --git a/node/node.go b/node/node.go index e1f4205ad..9b608d6f0 100644 --- a/node/node.go +++ b/node/node.go @@ -54,10 +54,10 @@ type nodeImpl struct { privValidator types.PrivValidator // local node's validator key // network - peerManager *p2p.PeerManager - router *p2p.Router - nodeInfoProducer func() *types.NodeInfo - nodeKey types.NodeKey // our node privkey + peerManager *p2p.PeerManager + router *p2p.Router + nodeInfo types.NodeInfo + nodeKey types.NodeKey // our node privkey // services eventSinks []indexer.EventSink @@ -249,25 +249,67 @@ func makeNode( makeCloser(closers)) } - router, err := createRouter(logger, nodeMetrics.p2p, func() *types.NodeInfo { return &nodeInfo }, nodeKey, peerManager, cfg, proxyApp) + // TODO construct node here: + node := &nodeImpl{ + config: cfg, + logger: logger, + genesisDoc: genDoc, + privValidator: privValidator, + + peerManager: peerManager, + nodeInfo: nodeInfo, + nodeKey: nodeKey, + + eventSinks: eventSinks, + + services: []service.Service{eventBus}, + + stateStore: stateStore, + blockStore: blockStore, + + shutdownOps: makeCloser(closers), + + rpcEnv: &rpccore.Environment{ + ProxyApp: proxyApp, + + StateStore: stateStore, + BlockStore: blockStore, + + PeerManager: peerManager, + + GenDoc: genDoc, + EventSinks: eventSinks, + EventBus: eventBus, + EventLog: eventLog, + Logger: logger.With("module", "rpc"), + Config: *cfg.RPC, + }, + } + + node.router, err = createRouter(logger, nodeMetrics.p2p, node.NodeInfo, nodeKey, peerManager, cfg, proxyApp) if err != nil { return nil, combineCloseError( fmt.Errorf("failed to create router: %w", err), makeCloser(closers)) } - mpReactor, mp, err := createMempoolReactor(logger, cfg, proxyApp, stateStore, nodeMetrics.mempool, - peerManager.Subscribe, router.OpenChannel, peerManager.GetHeight) - if err != nil { - return nil, combineCloseError(err, makeCloser(closers)) - } - evReactor, evPool, edbCloser, err := createEvidenceReactor(logger, cfg, dbProvider, - stateStore, blockStore, peerManager.Subscribe, router.OpenChannel, nodeMetrics.evidence, eventBus) + stateStore, blockStore, peerManager.Subscribe, node.router.OpenChannel, nodeMetrics.evidence, eventBus) closers = append(closers, edbCloser) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) } + node.services = append(node.services, evReactor) + node.rpcEnv.EvidencePool = evPool + node.evPool = evPool + + mpReactor, mp, err := createMempoolReactor(logger, cfg, proxyApp, stateStore, nodeMetrics.mempool, + peerManager.Subscribe, node.router.OpenChannel, peerManager.GetHeight) + if err != nil { + return nil, combineCloseError(err, makeCloser(closers)) + } + node.rpcEnv.Mempool = mp + node.services = append(node.services, mpReactor) // make block executor for consensus and blockchain reactors to execute blocks blockExec := sm.NewBlockExecutor( @@ -296,11 +338,14 @@ func makeNode( csReactor, csState, err := createConsensusReactor(ctx, cfg, stateStore, blockExec, blockStore, mp, evPool, privValidator, nodeMetrics.consensus, waitSync, eventBus, - peerManager, router.OpenChannel, logger, + peerManager, node.router.OpenChannel, logger, ) if err != nil { return nil, combineCloseError(err, makeCloser(closers)) } + node.services = append(node.services, csReactor) + node.rpcEnv.ConsensusState = csState + node.rpcEnv.ConsensusReactor = csReactor // Create the blockchain reactor. Note, we do not start block sync if we're // doing a state sync first. @@ -310,12 +355,14 @@ func makeNode( blockExec, blockStore, csReactor, - router.OpenChannel, + node.router.OpenChannel, peerManager.Subscribe, blockSync && !stateSync, nodeMetrics.consensus, eventBus, ) + node.services = append(node.services, bcReactor) + node.rpcEnv.BlockSyncReactor = bcReactor // Make ConsensusReactor. Don't enable fully if doing a state sync and/or block sync first. // FIXME We need to update metrics here, since other reactors don't have access to them. @@ -329,14 +376,15 @@ func makeNode( // FIXME The way we do phased startups (e.g. replay -> block sync -> consensus) is very messy, // we should clean this whole thing up. See: // https://github.com/tendermint/tendermint/issues/4644 - stateSyncReactor := statesync.NewReactor( + node.stateSync = stateSync + node.stateSyncReactor = statesync.NewReactor( ctx, genDoc.ChainID, genDoc.InitialHeight, *cfg.StateSync, logger.With("module", "statesync"), proxyApp, - router.OpenChannel, + node.router.OpenChannel, peerManager.Subscribe, stateStore, blockStore, @@ -345,61 +393,8 @@ func makeNode( eventBus, ) - var pexReactor service.Service = service.NopService{} if cfg.P2P.PexReactor { - pexReactor = pex.NewReactor(logger, peerManager, router.OpenChannel, peerManager.Subscribe) - } - node := &nodeImpl{ - config: cfg, - logger: logger, - genesisDoc: genDoc, - privValidator: privValidator, - - peerManager: peerManager, - router: router, - nodeInfoProducer: func() *types.NodeInfo { return &nodeInfo }, - nodeKey: nodeKey, - - eventSinks: eventSinks, - - services: []service.Service{ - eventBus, - evReactor, - mpReactor, - csReactor, - bcReactor, - pexReactor, - }, - - stateStore: stateStore, - blockStore: blockStore, - stateSyncReactor: stateSyncReactor, - stateSync: stateSync, - evPool: evPool, - - shutdownOps: makeCloser(closers), - - rpcEnv: &rpccore.Environment{ - ProxyApp: proxyApp, - EvidencePool: evPool, - ConsensusState: csState, - - StateStore: stateStore, - BlockStore: blockStore, - - ConsensusReactor: csReactor, - BlockSyncReactor: bcReactor, - - PeerManager: peerManager, - - GenDoc: genDoc, - EventSinks: eventSinks, - EventBus: eventBus, - EventLog: eventLog, - Mempool: mp, - Logger: logger.With("module", "rpc"), - Config: *cfg.RPC, - }, + node.services = append(node.services, pex.NewReactor(logger, peerManager, node.router.OpenChannel, peerManager.Subscribe)) } if cfg.Mode == config.ModeValidator { @@ -458,7 +453,7 @@ func (n *nodeImpl) OnStart(ctx context.Context) error { return err } - n.rpcEnv.NodeInfo = n.nodeInfoProducer().Copy() + n.rpcEnv.NodeInfo = n.nodeInfo // Start the RPC server before the P2P server // so we can eg. receive txs for the first block if n.config.RPC.ListenAddress != "" { @@ -644,6 +639,10 @@ func (n *nodeImpl) startPrometheusServer(ctx context.Context, addr string) *http return srv } +func (n *nodeImpl) NodeInfo() *types.NodeInfo { + return &n.nodeInfo +} + // EventBus returns the Node's EventBus. func (n *nodeImpl) EventBus() *eventbus.EventBus { return n.rpcEnv.EventBus diff --git a/node/node_test.go b/node/node_test.go index 86ed7960c..1a1fa6f81 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -147,7 +147,7 @@ func TestNodeSetAppVersion(t *testing.T) { assert.Equal(t, state.Version.Consensus.App, appVersion) // check version is set in node info - assert.Equal(t, n.nodeInfoProducer().ProtocolVersion.App, appVersion) + assert.Equal(t, n.nodeInfo.ProtocolVersion.App, appVersion) } func TestNodeSetPrivValTCP(t *testing.T) { From 025894c11d3a757cd8195ecb953d8bbe7000312d Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Wed, 6 Apr 2022 13:58:57 -0700 Subject: [PATCH 19/20] Forward-port changelogs from v0.34.17 and v0.34.18 to master. (#8265) * Forward-port changelogs from v0.34.17 and v0.34.18 to master. * Fix broken markdown links. --- CHANGELOG.md | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0216a533b..f759c42c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -230,6 +230,26 @@ Special thanks to external contributors on this release: @JayT106, - [cmd/tendermint/commands] [\#6623](https://github.com/tendermint/tendermint/pull/6623) replace `$HOME/.some/test/dir` with `t.TempDir` (@tanyabouman) - [statesync] \6807 Implement P2P state provider as an alternative to RPC (@cmwaters) +## v0.34.18 + +### BREAKING CHANGES + +- CLI/RPC/Config + - [cli] [\#8258](https://github.com/tendermint/tendermint/pull/8258) Fix a bug in the cli that caused `unsafe-reset-all` to panic + +## v0.34.17 + +### BREAKING CHANGES + +- CLI/RPC/Config + + - [cli] [\#8081](https://github.com/tendermint/tendermint/issues/8081) make the reset command safe to use (@marbar3778). + +### BUG FIXES + +- [consensus] [\#8079](https://github.com/tendermint/tendermint/issues/8079) start the timeout ticker before relay (backport #7844) (@creachadair). +- [consensus] [\#7992](https://github.com/tendermint/tendermint/issues/7992) [\#7994](https://github.com/tendermint/tendermint/issues/7994) change lock handling in handleMsg and reactor to alleviate issues gossiping during long ABCI calls (@williambanfield). + ## v0.34.16 Special thanks to external contributors on this release: @yihuang @@ -1953,7 +1973,7 @@ more details. - [rpc] [\#3269](https://github.com/tendermint/tendermint/issues/2826) Limit number of unique clientIDs with open subscriptions. Configurable via `rpc.max_subscription_clients` - [rpc] [\#3269](https://github.com/tendermint/tendermint/issues/2826) Limit number of unique queries a given client can subscribe to at once. Configurable via `rpc.max_subscriptions_per_client`. - [rpc] [\#3435](https://github.com/tendermint/tendermint/issues/3435) Default ReadTimeout and WriteTimeout changed to 10s. WriteTimeout can increased by setting `rpc.timeout_broadcast_tx_commit` in the config. - - [rpc/client] [\#3269](https://github.com/tendermint/tendermint/issues/3269) Update `EventsClient` interface to reflect new pubsub/eventBus API [ADR-33](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-033-pubsub.md). This includes `Subscribe`, `Unsubscribe`, and `UnsubscribeAll` methods. + - [rpc/client] [\#3269](https://github.com/tendermint/tendermint/issues/3269) Update `EventsClient` interface to reflect new pubsub/eventBus API [ADR-33](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-033-pubsub.md). This includes `Subscribe`, `Unsubscribe`, and `UnsubscribeAll` methods. * Apps - [abci] [\#3403](https://github.com/tendermint/tendermint/issues/3403) Remove `time_iota_ms` from BlockParams. This is a @@ -2006,7 +2026,7 @@ more details. - [blockchain] [\#3358](https://github.com/tendermint/tendermint/pull/3358) Fix timer leak in `BlockPool` (@guagualvcha) - [cmd] [\#3408](https://github.com/tendermint/tendermint/issues/3408) Fix `testnet` command's panic when creating non-validator configs (using `--n` flag) (@srmo) - [libs/db/remotedb/grpcdb] [\#3402](https://github.com/tendermint/tendermint/issues/3402) Close Iterator/ReverseIterator after use -- [libs/pubsub] [\#951](https://github.com/tendermint/tendermint/issues/951), [\#1880](https://github.com/tendermint/tendermint/issues/1880) Use non-blocking send when dispatching messages [ADR-33](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-033-pubsub.md) +- [libs/pubsub] [\#951](https://github.com/tendermint/tendermint/issues/951), [\#1880](https://github.com/tendermint/tendermint/issues/1880) Use non-blocking send when dispatching messages [ADR-33](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-033-pubsub.md) - [lite] [\#3364](https://github.com/tendermint/tendermint/issues/3364) Fix `/validators` and `/abci_query` proxy endpoints (@guagualvcha) - [p2p/conn] [\#3347](https://github.com/tendermint/tendermint/issues/3347) Reject all-zero shared secrets in the Diffie-Hellman step of secret-connection @@ -2710,7 +2730,7 @@ Special thanks to external contributors on this release: This release is mostly about the ConsensusParams - removing fields and enforcing MaxGas. It also addresses some issues found via security audit, removes various unused functions from `libs/common`, and implements -[ADR-012](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-012-peer-transport.md). +[ADR-012](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-012-peer-transport.md). BREAKING CHANGES: @@ -2791,7 +2811,7 @@ BREAKING CHANGES: - [abci] Added address of the original proposer of the block to Header - [abci] Change ABCI Header to match Tendermint exactly - [abci] [\#2159](https://github.com/tendermint/tendermint/issues/2159) Update use of `Validator` (see - [ADR-018](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-018-ABCI-Validators.md)): + [ADR-018](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-018-ABCI-Validators.md)): - Remove PubKey from `Validator` (so it's just Address and Power) - Introduce `ValidatorUpdate` (with just PubKey and Power) - InitChain and EndBlock use ValidatorUpdate @@ -2813,7 +2833,7 @@ BREAKING CHANGES: - [state] [\#1815](https://github.com/tendermint/tendermint/issues/1815) Validator set changes are now delayed by one block (!) - Add NextValidatorSet to State, changes on-disk representation of state - [state] [\#2184](https://github.com/tendermint/tendermint/issues/2184) Enforce ConsensusParams.BlockSize.MaxBytes (See - [ADR-020](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-020-block-size.md)). + [ADR-020](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-020-block-size.md)). - Remove ConsensusParams.BlockSize.MaxTxs - Introduce maximum sizes for all components of a block, including ChainID - [types] Updates to the block Header: @@ -2824,7 +2844,7 @@ BREAKING CHANGES: - [consensus] [\#2203](https://github.com/tendermint/tendermint/issues/2203) Implement BFT time - Timestamp in block must be monotonic and equal the median of timestamps in block's LastCommit - [crypto] [\#2239](https://github.com/tendermint/tendermint/issues/2239) Secp256k1 signature changes (See - [ADR-014](https://github.com/tendermint/tendermint/blob/develop/docs/architecture/adr-014-secp-malleability.md)): + [ADR-014](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-014-secp-malleability.md)): - format changed from DER to `r || s`, both little endian encoded as 32 bytes. - malleability removed by requiring `s` to be in canonical form. From 7678ab885093ab6b8b533fa24418c9ee8db1d0fe Mon Sep 17 00:00:00 2001 From: Sam Kleinman Date: Wed, 6 Apr 2022 17:50:14 -0400 Subject: [PATCH 20/20] statesync: tweak test performance (#8267) --- internal/statesync/reactor_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/statesync/reactor_test.go b/internal/statesync/reactor_test.go index f59a6e4ee..cef0735f2 100644 --- a/internal/statesync/reactor_test.go +++ b/internal/statesync/reactor_test.go @@ -196,11 +196,11 @@ func setup( } func TestReactor_Sync(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() const snapshotHeight = 7 - rts := setup(ctx, t, nil, nil, 2) + rts := setup(ctx, t, nil, nil, 100) chain := buildLightBlockChain(ctx, t, 1, 10, time.Now()) // app accepts any snapshot rts.conn.On("OfferSnapshot", ctx, mock.AnythingOfType("types.RequestOfferSnapshot")). @@ -224,8 +224,7 @@ func TestReactor_Sync(t *testing.T) { closeCh := make(chan struct{}) defer close(closeCh) - go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh, - rts.blockInCh, closeCh, 0) + go handleLightBlockRequests(ctx, t, chain, rts.blockOutCh, rts.blockInCh, closeCh, 0) go graduallyAddPeers(ctx, t, rts.peerUpdateCh, closeCh, 1*time.Second) go handleSnapshotRequests(ctx, t, rts.snapshotOutCh, rts.snapshotInCh, closeCh, []snapshot{ {