From 6f72cf891b7b5df681df08dca1d7c0af4d6153c1 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Thu, 23 Sep 2021 20:00:12 +0200 Subject: [PATCH 1/8] allow running of single node using the e2e app --- cmd/tendermint/commands/run_node.go | 2 +- internal/proxy/client.go | 7 +++++++ test/e2e/Makefile | 9 +++----- test/e2e/README.md | 32 ++++++++++++++++++++++++++++- test/e2e/app/app.go | 21 +++++++++++++++++-- test/e2e/app/snapshots.go | 2 +- test/e2e/app/state.go | 2 +- test/e2e/docker/Dockerfile | 2 +- test/e2e/node/built-in.toml | 4 ++++ test/e2e/{app => node}/config.go | 12 ++++++++++- test/e2e/{app => node}/main.go | 5 +++-- test/e2e/node/socket.toml | 5 +++++ 12 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 test/e2e/node/built-in.toml rename test/e2e/{app => node}/config.go (86%) rename test/e2e/{app => node}/main.go (98%) create mode 100644 test/e2e/node/socket.toml diff --git a/cmd/tendermint/commands/run_node.go b/cmd/tendermint/commands/run_node.go index c174fd967c4..f06a434c0b2 100644 --- a/cmd/tendermint/commands/run_node.go +++ b/cmd/tendermint/commands/run_node.go @@ -65,7 +65,7 @@ func AddNodeFlags(cmd *cobra.Command) { "proxy-app", config.ProxyApp, "proxy app address, or one of: 'kvstore',"+ - " 'persistent_kvstore' or 'noop' for local testing.") + " 'persistent_kvstore', 'test' or 'noop' for local testing.") cmd.Flags().String("abci", config.ABCI, "specify abci transport (socket | grpc)") // rpc flags diff --git a/internal/proxy/client.go b/internal/proxy/client.go index 072ddf3e0d7..c37014b3e35 100644 --- a/internal/proxy/client.go +++ b/internal/proxy/client.go @@ -6,6 +6,7 @@ import ( abciclient "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/example/kvstore" "github.com/tendermint/tendermint/abci/types" + e2e "github.com/tendermint/tendermint/test/e2e/app" ) // DefaultClientCreator returns a default ClientCreator, which will create a @@ -21,6 +22,12 @@ func DefaultClientCreator(addr, transport, dbDir string) (abciclient.Creator, io case "persistent_kvstore": app := kvstore.NewPersistentKVStoreApplication(dbDir) return abciclient.NewLocalCreator(app), app + case "test": + app, err := e2e.NewApplication(e2e.DefaultConfig(dbDir)) + if err != nil { + panic(err) + } + return abciclient.NewLocalCreator(app), noopCloser{} case "noop": return abciclient.NewLocalCreator(types.NewBaseApplication()), noopCloser{} default: diff --git a/test/e2e/Makefile b/test/e2e/Makefile index 2b41cc1cdee..59f62c7ad7b 100644 --- a/test/e2e/Makefile +++ b/test/e2e/Makefile @@ -1,13 +1,10 @@ -all: docker generator runner tests +all: node docker generator runner tests docker: docker build --tag tendermint/e2e-node -f docker/Dockerfile ../.. -# We need to build support for database backends into the app in -# order to build a binary with a Tendermint node in it (for built-in -# ABCI testing). -app: - go build -o build/app -tags badgerdb,boltdb,cleveldb,rocksdb ./app +node: + go build -o build/node ./node generator: go build -o build/generator ./generator diff --git a/test/e2e/README.md b/test/e2e/README.md index d737120c1cf..662e4f0ea35 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -142,10 +142,40 @@ Docker does not enable IPv6 by default. To do so, enter the following in } ``` -## Benchmarking testnets +## Benchmarking Testnets It is also possible to run a simple benchmark on a testnet. This is done through the `benchmark` command. This manages the entire process: setting up the environment, starting the test net, waiting for a considerable amount of blocks to be used (currently 100), and then returning the following metrics from the sample of the blockchain: - Average time to produce a block - Standard deviation of producing a block - Minimum and maximum time to produce a block + +## Running Individual Nodes + +The E2E test harness is designed to run several nodes of varying configurations within docker. It is also possible to run a single node in the case of running larger, geographically-dispersed testnets. To run a single node you can either run: + +**Built-in** + +```bash +make node +tendermint init validator +TMHOME=$HOME/.tendermint ./build/node ./node/built-in.toml +``` + +To make things simpler the e2e application can also be run in the tendermint binary +by running + +```bash +tendermint start --proxy-app test +``` + +**Socket** + +```bash +make node +tendermint init validator +tendermint start +./build/node ./node.socket.toml +``` + +Check `node/config.go` to see how the settings of the test application can be tweaked. \ No newline at end of file diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 26b10d32a93..14b3b1c1c8c 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -1,4 +1,4 @@ -package main +package app import ( "bytes" @@ -27,6 +27,23 @@ type Application struct { restoreChunks [][]byte } +type Config struct { + Dir string + SnapshotInterval uint64 + RetainBlocks uint64 + KeyType string + PersistInterval uint64 + ValidatorUpdates map[string]map[string]uint8 // height <-> pubkey <-> voting power +} + +func DefaultConfig(dir string) *Config { + return &Config{ + PersistInterval: 1, + SnapshotInterval: 100, + Dir: dir, + } +} + // NewApplication creates the application. func NewApplication(cfg *Config) (*Application, error) { state, err := NewState(filepath.Join(cfg.Dir, "state.json"), cfg.PersistInterval) @@ -134,7 +151,7 @@ func (app *Application) Commit() abci.ResponseCommit { if err != nil { panic(err) } - logger.Info("Created state sync snapshot", "height", snapshot.Height) + app.logger.Info("Created state sync snapshot", "height", snapshot.Height) } retainHeight := int64(0) if app.cfg.RetainBlocks > 0 { diff --git a/test/e2e/app/snapshots.go b/test/e2e/app/snapshots.go index 4ddb7ecdcd1..4ef20375ff8 100644 --- a/test/e2e/app/snapshots.go +++ b/test/e2e/app/snapshots.go @@ -1,5 +1,5 @@ // nolint: gosec -package main +package app import ( "encoding/json" diff --git a/test/e2e/app/state.go b/test/e2e/app/state.go index b34680c1b20..44192645309 100644 --- a/test/e2e/app/state.go +++ b/test/e2e/app/state.go @@ -1,5 +1,5 @@ //nolint: gosec -package main +package app import ( "crypto/sha256" diff --git a/test/e2e/docker/Dockerfile b/test/e2e/docker/Dockerfile index 68c7bc8363f..260df23f3a5 100644 --- a/test/e2e/docker/Dockerfile +++ b/test/e2e/docker/Dockerfile @@ -19,7 +19,7 @@ COPY . . RUN make build && cp build/tendermint /usr/bin/tendermint COPY test/e2e/docker/entrypoint* /usr/bin/ -RUN cd test/e2e && make app && cp build/app /usr/bin/app +RUN cd test/e2e && make node && cp build/node /usr/bin/app # Set up runtime directory. We don't use a separate runtime image since we need # e.g. leveldb and rocksdb which are already installed in the build image. diff --git a/test/e2e/node/built-in.toml b/test/e2e/node/built-in.toml new file mode 100644 index 00000000000..0a2146a58c9 --- /dev/null +++ b/test/e2e/node/built-in.toml @@ -0,0 +1,4 @@ +snapshot_interval = 100 +persist_interval = 1 +chain_id = "test-chain" +protocol = "builtin" diff --git a/test/e2e/app/config.go b/test/e2e/node/config.go similarity index 86% rename from test/e2e/app/config.go rename to test/e2e/node/config.go index d7e77653877..c857d3d213e 100644 --- a/test/e2e/app/config.go +++ b/test/e2e/node/config.go @@ -6,6 +6,8 @@ import ( "fmt" "github.com/BurntSushi/toml" + + "github.com/tendermint/tendermint/test/e2e/app" ) // Config is the application configuration. @@ -22,10 +24,18 @@ type Config struct { PrivValServer string `toml:"privval_server"` PrivValKey string `toml:"privval_key"` PrivValState string `toml:"privval_state"` - Misbehaviors map[string]string `toml:"misbehaviors"` KeyType string `toml:"key_type"` } +func (cfg *Config) App() *app.Config { + return &app.Config{ + SnapshotInterval: cfg.SnapshotInterval, + RetainBlocks: cfg.RetainBlocks, + KeyType: cfg.KeyType, + ValidatorUpdates: cfg.ValidatorUpdates, + } +} + // LoadConfig loads the configuration from disk. func LoadConfig(file string) (*Config, error) { cfg := &Config{ diff --git a/test/e2e/app/main.go b/test/e2e/node/main.go similarity index 98% rename from test/e2e/app/main.go rename to test/e2e/node/main.go index 1d680652447..222a6883fac 100644 --- a/test/e2e/app/main.go +++ b/test/e2e/node/main.go @@ -30,6 +30,7 @@ import ( grpcprivval "github.com/tendermint/tendermint/privval/grpc" privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval" rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server" + "github.com/tendermint/tendermint/test/e2e/app" e2e "github.com/tendermint/tendermint/test/e2e/pkg" ) @@ -97,7 +98,7 @@ func run(configFile string) error { // startApp starts the application server, listening for connections from Tendermint. func startApp(cfg *Config) error { - app, err := NewApplication(cfg) + app, err := app.NewApplication(cfg.App()) if err != nil { return err } @@ -118,7 +119,7 @@ func startApp(cfg *Config) error { // // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper. func startNode(cfg *Config) error { - app, err := NewApplication(cfg) + app, err := app.NewApplication(cfg.App()) if err != nil { return err } diff --git a/test/e2e/node/socket.toml b/test/e2e/node/socket.toml new file mode 100644 index 00000000000..b353e7d55d1 --- /dev/null +++ b/test/e2e/node/socket.toml @@ -0,0 +1,5 @@ +snapshot_interval = 100 +persist_interval = 1 +chain_id = "test-chain" +protocol = "socket" +listen = "tcp://127.0.0.1:26658" \ No newline at end of file From 000c1934ca688b86a742600f6defff4afc440b29 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Fri, 24 Sep 2021 16:05:18 +0200 Subject: [PATCH 2/8] add more descriptions to the e2e app config --- test/e2e/app/app.go | 44 +++++++++++++++++++++++++++++++++------ test/e2e/node/config.go | 1 + test/e2e/node/socket.toml | 2 +- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 14b3b1c1c8c..0a0194c9803 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -27,13 +27,45 @@ type Application struct { restoreChunks [][]byte } +// Config allows for the setting of high level parameters for running the e2e Application +// KeyType and ValidatorUpdates must be the same for all nodes running the same application. type Config struct { - Dir string - SnapshotInterval uint64 - RetainBlocks uint64 - KeyType string - PersistInterval uint64 - ValidatorUpdates map[string]map[string]uint8 // height <-> pubkey <-> voting power + // The directory with which state.json will be persisted in. Usually $HOME/.tendermint/data + Dir string `toml:"dir"` + + // SnapshotInterval specifies the height interval at which the application + // will take state sync snapshots. Defaults to 0 (disabled). + SnapshotInterval uint64 `toml:"snapshot_interval"` + + // RetainBlocks specifies the number of recent blocks to retain. Defaults to + // 0, which retains all blocks. Must be greater that PersistInterval, + // SnapshotInterval and EvidenceAgeHeight. + RetainBlocks uint64 `toml:"retain_blocks"` + + // KeyType sets the curve that will be used by validators. + // Options are ed25519 & secp256k1 + KeyType string `toml:"key_type"` + + // PersistInterval specifies the height interval at which the application + // will persist state to disk. Defaults to 1 (every height), setting this to + // 0 disables state persistence. + PersistInterval uint64 `toml:"persist_interval"` + + // ValidatorUpdates is a map of heights to validator names and their power, + // and will be returned by the ABCI application. For example, the following + // changes the power of validator01 and validator02 at height 1000: + // + // [validator_update.1000] + // validator01 = 20 + // validator02 = 10 + // + // Specifying height 0 returns the validator update during InitChain. The + // application returns the validator updates as-is, i.e. removing a + // validator must be done by returning it with power 0, and any validators + // not specified are not changed. + // + // height <-> pubkey <-> voting power + ValidatorUpdates map[string]map[string]uint8 `toml:"validator_update"` } func DefaultConfig(dir string) *Config { diff --git a/test/e2e/node/config.go b/test/e2e/node/config.go index c857d3d213e..7481bc03ef0 100644 --- a/test/e2e/node/config.go +++ b/test/e2e/node/config.go @@ -27,6 +27,7 @@ type Config struct { KeyType string `toml:"key_type"` } +// App extracts out the application specific configuration parameters func (cfg *Config) App() *app.Config { return &app.Config{ SnapshotInterval: cfg.SnapshotInterval, diff --git a/test/e2e/node/socket.toml b/test/e2e/node/socket.toml index b353e7d55d1..2f7913e62c2 100644 --- a/test/e2e/node/socket.toml +++ b/test/e2e/node/socket.toml @@ -2,4 +2,4 @@ snapshot_interval = 100 persist_interval = 1 chain_id = "test-chain" protocol = "socket" -listen = "tcp://127.0.0.1:26658" \ No newline at end of file +listen = "tcp://127.0.0.1:26658" From e14d4b6d25562a39185c7f5296ffbda1b9ae637a Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Fri, 24 Sep 2021 16:06:55 +0200 Subject: [PATCH 3/8] use e2e instead of test as the name of the proxy app --- internal/proxy/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/proxy/client.go b/internal/proxy/client.go index c37014b3e35..a8b73318f96 100644 --- a/internal/proxy/client.go +++ b/internal/proxy/client.go @@ -22,7 +22,7 @@ func DefaultClientCreator(addr, transport, dbDir string) (abciclient.Creator, io case "persistent_kvstore": app := kvstore.NewPersistentKVStoreApplication(dbDir) return abciclient.NewLocalCreator(app), app - case "test": + case "e2e": app, err := e2e.NewApplication(e2e.DefaultConfig(dbDir)) if err != nil { panic(err) From 78627371425230d0bb6650616869e28a3ea1589a Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Fri, 24 Sep 2021 16:08:37 +0200 Subject: [PATCH 4/8] use e2e instead of test --- cmd/tendermint/commands/run_node.go | 2 +- internal/proxy/client.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/tendermint/commands/run_node.go b/cmd/tendermint/commands/run_node.go index f06a434c0b2..1e310f5eb99 100644 --- a/cmd/tendermint/commands/run_node.go +++ b/cmd/tendermint/commands/run_node.go @@ -65,7 +65,7 @@ func AddNodeFlags(cmd *cobra.Command) { "proxy-app", config.ProxyApp, "proxy app address, or one of: 'kvstore',"+ - " 'persistent_kvstore', 'test' or 'noop' for local testing.") + " 'persistent_kvstore', 'e2e' or 'noop' for local testing.") cmd.Flags().String("abci", config.ABCI, "specify abci transport (socket | grpc)") // rpc flags diff --git a/internal/proxy/client.go b/internal/proxy/client.go index a8b73318f96..ddb9a928de7 100644 --- a/internal/proxy/client.go +++ b/internal/proxy/client.go @@ -11,7 +11,7 @@ import ( // DefaultClientCreator returns a default ClientCreator, which will create a // local client if addr is one of: 'kvstore', -// 'persistent_kvstore' or 'noop', otherwise - a remote client. +// 'persistent_kvstore', 'e2e', or 'noop', otherwise - a remote client. // // The Closer is a noop except for persistent_kvstore applications, // which will clean up the store. From 9e21167e006427da650cadf2c65ff84b42a1c135 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Fri, 24 Sep 2021 16:10:49 +0200 Subject: [PATCH 5/8] update changelog --- CHANGELOG_PENDING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 1c8c2b81e12..d0660753f8b 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -24,6 +24,8 @@ Friendly reminder: We have a [bug bounty program](https://hackerone.com/tendermi ### FEATURES +- [\#6982](https://github.com/tendermint/tendermint/pull/6982) tendermint binary has built-in suppport for running the e2e application (with state sync support) (@cmwaters). + ### IMPROVEMENTS ### BUG FIXES From 15b0a5c972f805e74a710ff0e94048124b7ddca2 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Fri, 24 Sep 2021 17:01:44 +0200 Subject: [PATCH 6/8] fix makefile --- test/e2e/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/Makefile b/test/e2e/Makefile index 59f62c7ad7b..8457dc008d0 100644 --- a/test/e2e/Makefile +++ b/test/e2e/Makefile @@ -15,4 +15,4 @@ runner: tests: go test -o build/tests ./tests -.PHONY: all app docker generator runner tests +.PHONY: all app docker generator runner tests node From ec1dbfe258dfea8192223a3ca2caea4800f027f5 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Fri, 24 Sep 2021 17:33:22 +0200 Subject: [PATCH 7/8] fix makefile --- test/e2e/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/Makefile b/test/e2e/Makefile index 8457dc008d0..23cf4d0398d 100644 --- a/test/e2e/Makefile +++ b/test/e2e/Makefile @@ -1,10 +1,10 @@ -all: node docker generator runner tests +all: docker generator runner tests docker: docker build --tag tendermint/e2e-node -f docker/Dockerfile ../.. node: - go build -o build/node ./node + go build -o build/node -tags badgerdb,boltdb,cleveldb,rocksdb ./node generator: go build -o build/generator ./generator @@ -15,4 +15,4 @@ runner: tests: go test -o build/tests ./tests -.PHONY: all app docker generator runner tests node +.PHONY: all docker generator runner tests node From d2a199dcac32596a6964e1997ae8776c02d69766 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Mon, 27 Sep 2021 15:28:26 +0200 Subject: [PATCH 8/8] fix e2e test --- test/e2e/README.md | 4 +++- test/e2e/node/config.go | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index 662e4f0ea35..00bce5ad8aa 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -166,9 +166,11 @@ To make things simpler the e2e application can also be run in the tendermint bin by running ```bash -tendermint start --proxy-app test +tendermint start --proxy-app e2e ``` +However this won't offer the same level of configurability of the application. + **Socket** ```bash diff --git a/test/e2e/node/config.go b/test/e2e/node/config.go index 7481bc03ef0..fa7dcc497eb 100644 --- a/test/e2e/node/config.go +++ b/test/e2e/node/config.go @@ -30,10 +30,12 @@ type Config struct { // App extracts out the application specific configuration parameters func (cfg *Config) App() *app.Config { return &app.Config{ + Dir: cfg.Dir, SnapshotInterval: cfg.SnapshotInterval, RetainBlocks: cfg.RetainBlocks, KeyType: cfg.KeyType, ValidatorUpdates: cfg.ValidatorUpdates, + PersistInterval: cfg.PersistInterval, } }