From 850455f8bbdfad27a6a89b56f3c64697bea1b40b Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 3 Jul 2019 11:28:32 +0200 Subject: [PATCH] Introduce flag to enable sentry nodes to participate in grandpa gossip Given the following situation: A validator 'A' is not supposed to be connected to the public internet to protect it from e.g. a DoS attack. Instead it connects to a sentry node 'sentry-A' which connects to the public internet. Validator 'B' can reach validator 'A' via sentry node 'sentry-A' and vice versa. A sentry node needs to participate in the grandpa gossip without becoming a validator itself in order to forward these message to its validator. This commit adds a new command line flag (`--grandpa-voter`) forcing a node to participate in the grandpa voting process even though no `--key` was specified. Due to the fact that it does not have a key, it does not become a validator in the network. In order to simulate the above situation this commit also adds a Docker Compose file (`scripts/sentry-node/docker-compose.yml`) with further documentation. --- core/cli/src/lib.rs | 2 + core/cli/src/params.rs | 5 + core/service/src/config.rs | 9 +- core/service/test/src/lib.rs | 1 + node/cli/src/service.rs | 5 +- scripts/sentry-node/docker-compose.yml | 138 +++++++++++++++++++++++++ 6 files changed, 155 insertions(+), 5 deletions(-) create mode 100644 scripts/sentry-node/docker-compose.yml diff --git a/core/cli/src/lib.rs b/core/cli/src/lib.rs index 4fe5ac3a829c9..de0640e0dfb2e 100644 --- a/core/cli/src/lib.rs +++ b/core/cli/src/lib.rs @@ -443,6 +443,8 @@ where config.roles = role; config.disable_grandpa = cli.no_grandpa; + config.grandpa_voter = cli.grandpa_voter; + let is_dev = cli.shared_params.dev; diff --git a/core/cli/src/params.rs b/core/cli/src/params.rs index 0cdc633188d7d..77e42fa192ab2 100644 --- a/core/cli/src/params.rs +++ b/core/cli/src/params.rs @@ -305,6 +305,11 @@ pub struct RunCmd { #[structopt(long = "no-grandpa")] pub no_grandpa: bool, + /// Run GRANDPA voter even when no additional key seed via `--key` is specified. This can for example be of interest + /// when running a sentry node in front of a validator, thus needing to forward GRANDPA gossip messages. + #[structopt(long = "grandpa-voter")] + pub grandpa_voter: bool, + /// Experimental: Run in light client mode #[structopt(long = "light")] pub light: bool, diff --git a/core/service/src/config.rs b/core/service/src/config.rs index 92f9882ff9c5e..e101c804ecf39 100644 --- a/core/service/src/config.rs +++ b/core/service/src/config.rs @@ -51,8 +51,8 @@ pub struct Configuration { pub database_cache_size: Option, /// Size of internal state cache in Bytes pub state_cache_size: usize, - /// Size in percent of cache size dedicated to child tries - pub state_cache_child_ratio: Option, + /// Size in percent of cache size dedicated to child tries + pub state_cache_child_ratio: Option, /// Pruning settings. pub pruning: PruningMode, /// Additional key seeds. @@ -86,6 +86,9 @@ pub struct Configuration { pub force_authoring: bool, /// Disable GRANDPA when running in validator mode pub disable_grandpa: bool, + /// Run GRANDPA voter even when no additional key seed is specified. This can for example be of interest when + /// running a sentry node in front of a validator, thus needing to forward GRANDPA gossip messages. + pub grandpa_voter: bool, /// Node keystore's password pub password: String, } @@ -121,6 +124,7 @@ impl Configuration String { let commit_dash = if impl_commit.is_empty() { "" } else { "-" }; format!("{}{}{}-{}", impl_version, commit_dash, impl_commit, platform()) } - diff --git a/core/service/test/src/lib.rs b/core/service/test/src/lib.rs index 5abd97fada7c8..0c8c8df9ec759 100644 --- a/core/service/test/src/lib.rs +++ b/core/service/test/src/lib.rs @@ -192,6 +192,7 @@ fn node_config ( offchain_worker: false, force_authoring: false, disable_grandpa: false, + grandpa_voter: false, password: "".to_string(), } } diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index e27baca8e6995..79ca8918c1b66 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -124,7 +124,7 @@ construct_service_factory! { }; match config.local_key { - None => { + None if !service.config.grandpa_voter => { service.spawn_task(Box::new(grandpa::run_grandpa_observer( config, link_half, @@ -132,7 +132,8 @@ construct_service_factory! { service.on_exit(), )?)); }, - Some(_) => { + // Either config.local_key is set, or user forced voter service via `--grandpa-voter` flag. + _ => { let telemetry_on_connect = TelemetryOnConnect { telemetry_connection_sinks: service.telemetry_on_connect_stream(), }; diff --git a/scripts/sentry-node/docker-compose.yml b/scripts/sentry-node/docker-compose.yml new file mode 100644 index 0000000000000..e784b29f9fd1c --- /dev/null +++ b/scripts/sentry-node/docker-compose.yml @@ -0,0 +1,138 @@ +# Docker compose file to simulate a sentry node setup. +# +# +# Setup: +# +# Validator A is not supposed to be connected to the public internet. Instead it +# connects to a sentry node (sentry-a) which connects to the public internet. +# Validator B can reach validator A via sentry node A and vice versa. +# +# +# Usage: +# +# 1. Build `target/debug/substrate` binary: `cargo build` +# +# 2. Start networks and containers: `sudo docker-compose -f scripts/sentry-node/docker-compose.yml up` +# +# 3. Reach: +# - polkadot/apps on localhost:3000 +# - validator-a: localhost:9944 +# - validator-b: localhost:9945 +# - sentry-a: localhost:9946 + +version: "3.7" +services: + + validator-a: + ports: + - "9944:9944" + volumes: + - ../../target/debug/substrate:/usr/local/bin/substrate + image: parity/substrate + networks: + - network-a + command: + # Local node id: QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR + - "--node-key" + - "0000000000000000000000000000000000000000000000000000000000000001" + - "--base-path" + - "/tmp/alice" + - "--chain=local" + - "--key" + - "//Alice" + - "--port" + - "30333" + - "--validator" + - "--name" + - "AlicesNode" + - "--bootnodes" + - "/dns4/validator-b/tcp/30333/p2p/QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk" + # Not only bind to localhost. + - "--ws-external" + - "--rpc-external" + # - "--log" + # - "sub-libp2p=trace" + # - "--log" + # - "afg=trace" + - "--no-telemetry" + - "--rpc-cors" + - "all" + + sentry-a: + image: parity/substrate + ports: + - "9946:9944" + volumes: + - ../../target/debug/substrate:/usr/local/bin/substrate + networks: + - network-a + - internet + command: + # Local node id: QmV7EhW6J6KgmNdr558RH1mPx2xGGznW7At4BhXzntRFsi + - "--node-key" + - "0000000000000000000000000000000000000000000000000000000000000003" + - "--base-path" + - "/tmp/sentry" + - "--chain=local" + # Don't configure a key, as sentry-a is not a validator. + # - "--key" + # - "//Charlie" + - "--port" + - "30333" + # sentry-a is not a validator. + # - "--validator" + - "--name" + - "CharliesNode" + - "--bootnodes" + - "/dns4/validator-a/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR" + - "--bootnodes" + - "/dns4/validator-b/tcp/30333/p2p/QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk" + - "--no-telemetry" + - "--rpc-cors" + - "all" + # Not only bind to localhost. + - "--ws-external" + - "--rpc-external" + # Make sure sentry-a still participates as a grandpa voter to forward + # grandpa finality gossip messages. + - "--grandpa-voter" + + validator-b: + image: parity/substrate + ports: + - "9945:9944" + volumes: + - ../../target/debug/substrate:/usr/local/bin/substrate + networks: + - internet + command: + # Local node id: QmSVnNf9HwVMT1Y4cK1P6aoJcEZjmoTXpjKBmAABLMnZEk + - "--node-key" + - "0000000000000000000000000000000000000000000000000000000000000002" + - "--base-path" + - "/tmp/bob" + - "--chain=local" + - "--key" + - "//Bob" + - "--port" + - "30333" + - "--validator" + - "--name" + - "BobsNode" + - "--bootnodes" + - "/dns4/validator-a/tcp/30333/p2p/QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR" + - "--no-telemetry" + - "--rpc-cors" + - "all" + # Not only bind to localhost. + - "--ws-external" + - "--rpc-external" + + ui: + image: polkadot-js/apps + ports: + - "3000:80" + +networks: + network-a: + internet: