Rialto test network setup (#163)

* Dockerfile for OpenEth.

* Add relayer dockerfile.

* Add docker-compose.

* Working on the relay.

* Bump a bunch of deps.

* Change relay branch.

* Running a 3-validators poa network.

* Add bridge nodes.

* Conditional compilation of bridge configs.

* Fix genesis hash.

* Disable features build.

* Disable empty steps.

* Work on sub2eth

* Add some logs.

* More logs.

* Fix compilation.

* Add chain-id parameter to relay.

* Unify bridge-hash.

* Update the hash.

* Ditch sub2eth for now.

* Add some docs & proxy configuration.

* Fixes.

* Fix remaining issues.

* Increase health timeout.

* Make sure to install curl for health monitoring.

* Fix kovan.

* Fix build.

* Create if does not exist.

* Fix benches.

* Revert CLI params requirements.

* cargo fmt --all

* Apply suggestions from code review

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>

* Add some docs.

* Update BRIDGE_HASH to master

* Duplicate compose file.

* Rename testpoa to Rialto.

* Fix borked merge.

* Fix entrypoints to take arguments.

Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
This commit is contained in:
Tomasz Drwięga
2020-07-17 16:39:32 +02:00
committed by Bastian Köcher
parent 00bd13f8cd
commit bebb5e6035
11 changed files with 300 additions and 52 deletions
+37 -1
View File
@@ -157,4 +157,40 @@ The folder structure of the bridge relay is as follows:
```
## Running the Bridge
👷 Under Construction 👷‍♀️
To run the Bridge you need to be able to connect to the RPC interface of nodes on each side of the
bridge (home & foreign chain).
You can build the relayer using [./Dockerfile](Dockerfile), which will use all the local source
files,
or you can use an image that is designed to build from Github repo sources (`master` branch by
default, configurable via `build-arg`):
```bash
docker build \
https://raw.githubusercontent.com/paritytech/parity-bridges-common/master/deployments/rialto/Bridge.Dockerfile \
-t poa-relay
docker run -it poa-relay
```
By default the relayer is configured to connect to OpenEthereum `--dev` chain node and Substrate
`bridge-node` running in a `--dev` mode.
To build the `bridge-node`:
```bash
docker build \
https://raw.githubusercontent.com/paritytech/parity-bridges-common/master/deployments/rialto/Bridge.Dockerfile \
-t bridge-node \
--build-arg PROJECT=bridge-node
docker run -it bridge-node
```
And to build `OpenEthereum` with bridge support:
```
docker build \
https://raw.githubusercontent.com/paritytech/parity-bridges-common/master/deployments/rialto/OpenEthereum.Dockerfile
-t openethereum
docker run it openethereum
```
See [./deployments/README.md](Deployments README) to learn more about how to run
a more sophisticated test network using `docker-compose` setup.
+9 -2
View File
@@ -16,9 +16,14 @@ futures = "0.3.5"
jsonrpc-core = "14.2.0"
log = "0.4.8"
structopt = "0.3.15"
bridge-node-runtime = { version = "0.1.0", path = "../runtime" }
sp-bridge-eth-poa = { version = "0.1.0", path = "../../../primitives/ethereum-poa" }
[dependencies.bridge-node-runtime]
version = "0.1.0"
path = "../runtime"
default-features = false
features = ["std"]
[dependencies.sc-cli]
version = "0.8.0-rc4"
tag = 'v2.0.0-rc4'
@@ -141,7 +146,9 @@ tag = 'v2.0.0-rc4'
git = "https://github.com/paritytech/substrate.git"
[features]
default = []
default = ["bridge-rialto"]
bridge-kovan = ["bridge-node-runtime/bridge-kovan"]
bridge-rialto = ["bridge-node-runtime/bridge-rialto"]
runtime-benchmarks = [
"bridge-node-runtime/runtime-benchmarks",
]
+4 -4
View File
@@ -153,7 +153,7 @@ fn testnet_genesis(
pallet_aura: Some(AuraConfig {
authorities: Vec::new(),
}),
pallet_bridge_eth_poa: load_kovan_config(),
pallet_bridge_eth_poa: load_bridge_config(),
pallet_grandpa: Some(GrandpaConfig {
authorities: Vec::new(),
}),
@@ -167,10 +167,10 @@ fn testnet_genesis(
}
}
fn load_kovan_config() -> Option<BridgeEthPoAConfig> {
fn load_bridge_config() -> Option<BridgeEthPoAConfig> {
Some(BridgeEthPoAConfig {
initial_header: bridge_node_runtime::kovan::kovan_genesis_header(),
initial_header: bridge_node_runtime::bridge::genesis_header(),
initial_difficulty: 0.into(),
initial_validators: bridge_node_runtime::kovan::kovan_genesis_validators(),
initial_validators: bridge_node_runtime::bridge::genesis_validators(),
})
}
+4 -1
View File
@@ -224,7 +224,9 @@ package = "substrate-wasm-builder-runner"
git = "https://github.com/paritytech/substrate/"
[features]
default = ["std"]
default = ["std", "bridge-rialto"]
bridge-kovan = []
bridge-rialto = []
std = [
"pallet-aura/std",
"pallet-balances/std",
@@ -266,4 +268,5 @@ runtime-benchmarks = [
"pallet-bridge-eth-poa/runtime-benchmarks",
"sp-bridge-eth-poa/test-helpers",
"sp-runtime/runtime-benchmarks",
"bridge-kovan",
]
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! We want to use a different validator configuration for benchmarking than what's used in Kovan
//! or in our Rialto test network. However, we can't configure a new validator set on the fly which
//! means we need to wire the runtime together like this
use pallet_bridge_eth_poa::{ValidatorsConfiguration, ValidatorsSource};
use sp_std::vec;
pub use crate::kovan::{
genesis_header, genesis_validators, BridgeAuraConfiguration, FinalityVotesCachingInterval, PruningStrategy,
};
frame_support::parameter_types! {
pub BridgeValidatorsConfiguration: pallet_bridge_eth_poa::ValidatorsConfiguration = bench_validator_config();
}
fn bench_validator_config() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(vec![[1; 20].into()])),
(1, ValidatorsSource::Contract([3; 20].into(), vec![[1; 20].into()])),
])
}
+19 -9
View File
@@ -16,10 +16,20 @@
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{AuraConfiguration, PruningStrategy, ValidatorsConfiguration, ValidatorsSource};
use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as BridgePruningStrategy, ValidatorsConfiguration, ValidatorsSource,
};
use sp_bridge_eth_poa::{Address, Header, U256};
use sp_std::prelude::*;
frame_support::parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(16);
pub BridgeAuraConfiguration: AuraConfiguration =
kovan_aura_configuration();
pub BridgeValidatorsConfiguration: ValidatorsConfiguration =
kovan_validators_configuration();
}
/// Max number of finalized headers to keep. It is equivalent of ~24 hours of
/// finalized blocks on current Kovan chain.
const FINALIZED_HEADERS_TO_KEEP: u64 = 20_000;
@@ -41,7 +51,7 @@ pub fn kovan_aura_configuration() -> AuraConfiguration {
/// Validators configuration for Kovan chain.
pub fn kovan_validators_configuration() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(kovan_genesis_validators())),
(0, ValidatorsSource::List(genesis_validators())),
(
10960440,
ValidatorsSource::List(vec![
@@ -67,7 +77,7 @@ pub fn kovan_validators_configuration() -> ValidatorsConfiguration {
}
/// Genesis validators set of Kovan chain.
pub fn kovan_genesis_validators() -> Vec<Address> {
pub fn genesis_validators() -> Vec<Address> {
vec![
hex!("00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED").into(),
hex!("00427feae2419c15b89d1c21af10d1b6650a4d3d").into(),
@@ -82,7 +92,7 @@ pub fn kovan_genesis_validators() -> Vec<Address> {
}
/// Genesis header of the Kovan chain.
pub fn kovan_genesis_header() -> Header {
pub fn genesis_header() -> Header {
Header {
parent_hash: Default::default(),
timestamp: 0,
@@ -114,9 +124,9 @@ pub fn kovan_genesis_header() -> Header {
/// claims from finalized headers. And if we're pruning unfinalized headers, then
/// some claims may never be accepted.
#[derive(Default, RuntimeDebug)]
pub struct KovanPruningStrategy;
pub struct PruningStrategy;
impl PruningStrategy for KovanPruningStrategy {
impl BridgePruningStrategy for PruningStrategy {
fn pruning_upper_bound(&mut self, _best_number: u64, best_finalized_number: u64) -> u64 {
best_finalized_number
.checked_sub(FINALIZED_HEADERS_TO_KEEP)
@@ -131,19 +141,19 @@ mod tests {
#[test]
fn pruning_strategy_keeps_enough_headers() {
assert_eq!(
KovanPruningStrategy::default().pruning_upper_bound(100_000, 10_000),
PruningStrategy::default().pruning_upper_bound(100_000, 10_000),
0,
"10_000 <= 20_000 => nothing should be pruned yet",
);
assert_eq!(
KovanPruningStrategy::default().pruning_upper_bound(100_000, 20_000),
PruningStrategy::default().pruning_upper_bound(100_000, 20_000),
0,
"20_000 <= 20_000 => nothing should be pruned yet",
);
assert_eq!(
KovanPruningStrategy::default().pruning_upper_bound(100_000, 30_000),
PruningStrategy::default().pruning_upper_bound(100_000, 30_000),
10_000,
"20_000 <= 30_000 => we're ready to prune first 10_000 headers",
);
+29 -34
View File
@@ -25,7 +25,20 @@
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
pub mod exchange;
#[cfg(feature = "runtime-benchmarks")]
pub mod benches;
#[cfg(feature = "bridge-kovan")]
pub mod kovan;
#[cfg(feature = "bridge-rialto")]
pub mod rialto;
#[cfg(feature = "runtime-benchmarks")]
pub use benches as bridge;
#[cfg(all(feature = "bridge-kovan", not(feature = "runtime-benchmarks")))]
pub use kovan as bridge;
#[cfg(all(feature = "bridge-rialto", not(feature = "runtime-benchmarks")))]
pub use rialto as bridge;
use codec::{Decode, Encode};
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
@@ -216,39 +229,11 @@ impl pallet_aura::Trait for Runtime {
type AuthorityId = AuraId;
}
// We want to use a different validator configuration for benchmarking than what's used in Kovan,
// but we can't configure a new validator set on the fly which means we need to wire the runtime
// together like this
#[cfg(feature = "runtime-benchmarks")]
use pallet_bridge_eth_poa::{ValidatorsConfiguration, ValidatorsSource};
#[cfg(feature = "runtime-benchmarks")]
parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(16);
pub KovanAuraConfiguration: pallet_bridge_eth_poa::AuraConfiguration = kovan::kovan_aura_configuration();
pub KovanValidatorsConfiguration: pallet_bridge_eth_poa::ValidatorsConfiguration = bench_validator_config();
}
#[cfg(feature = "runtime-benchmarks")]
fn bench_validator_config() -> ValidatorsConfiguration {
ValidatorsConfiguration::Multi(vec![
(0, ValidatorsSource::List(vec![[1; 20].into()])),
(1, ValidatorsSource::Contract([3; 20].into(), vec![[1; 20].into()])),
])
}
#[cfg(not(feature = "runtime-benchmarks"))]
parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(16);
pub KovanAuraConfiguration: pallet_bridge_eth_poa::AuraConfiguration = kovan::kovan_aura_configuration();
pub KovanValidatorsConfiguration: pallet_bridge_eth_poa::ValidatorsConfiguration = kovan::kovan_validators_configuration();
}
impl pallet_bridge_eth_poa::Trait for Runtime {
type AuraConfiguration = KovanAuraConfiguration;
type FinalityVotesCachingInterval = FinalityVotesCachingInterval;
type ValidatorsConfiguration = KovanValidatorsConfiguration;
type PruningStrategy = kovan::KovanPruningStrategy;
type AuraConfiguration = bridge::BridgeAuraConfiguration;
type FinalityVotesCachingInterval = bridge::FinalityVotesCachingInterval;
type ValidatorsConfiguration = bridge::BridgeValidatorsConfiguration;
type PruningStrategy = bridge::PruningStrategy;
type OnHeadersSubmitted = ();
}
@@ -641,8 +626,18 @@ impl_runtime_apis! {
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark};
let mut batches = Vec::<BenchmarkBatch>::new();
let whitelist: Vec<Vec<u8>> = vec![];
let whitelist: Vec<Vec<u8>> = vec![
// Block Number
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec(),
// Execution Phase
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec(),
// Event Count
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(),
// System Events
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec(),
// Caller 0 Account
hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da946c154ffd9992e395af90b5b13cc6f295c77033fce8a9045824a6690bbf99c6db269502f0a8d1d2a008542d5690a0749").to_vec(),
];
let params = (&pallet, &benchmark, &lowest_range_values, &highest_range_values, &steps, repeat, &whitelist);
use pallet_bridge_currency_exchange::benchmarking::{
+141
View File
@@ -0,0 +1,141 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as TPruningStrategy, ValidatorsConfiguration, ValidatorsSource,
};
use sp_bridge_eth_poa::{Address, Header, U256};
use sp_std::prelude::*;
frame_support::parameter_types! {
pub const FinalityVotesCachingInterval: Option<u64> = Some(8);
pub BridgeAuraConfiguration: AuraConfiguration =
aura_configuration();
pub BridgeValidatorsConfiguration: ValidatorsConfiguration =
validators_configuration();
}
/// Max number of finalized headers to keep.
const FINALIZED_HEADERS_TO_KEEP: u64 = 5_000;
/// Aura engine configuration for Rialto chain.
pub fn aura_configuration() -> AuraConfiguration {
AuraConfiguration {
empty_steps_transition: 0xfffffffff,
strict_empty_steps_transition: 0,
validate_step_transition: 0,
validate_score_transition: 0,
two_thirds_majority_transition: u64::max_value(),
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::max_value(),
maximum_extra_data_size: 0x20,
}
}
/// Validators configuration for Rialto chain.
pub fn validators_configuration() -> ValidatorsConfiguration {
ValidatorsConfiguration::Single(ValidatorsSource::List(genesis_validators()))
}
/// Genesis validators set of Rialto chain.
pub fn genesis_validators() -> Vec<Address> {
vec![
hex!("005e714f896a8b7cede9d38688c1a81de72a58e4").into(),
hex!("007594304039c2937a12220338aab821d819f5a4").into(),
hex!("004e7a39907f090e19b0b80a277e77b72b22e269").into(),
]
}
/// Genesis header of the Rialto chain.
///
/// To obtain genesis header from a running node, invoke:
/// ```bash
/// $ http localhost:8545 jsonrpc=2.0 id=1 method=eth_getBlockByNumber params:='["earliest", false]' -v
/// ```
pub fn genesis_header() -> Header {
Header {
parent_hash: Default::default(),
timestamp: 0,
number: 0,
author: Default::default(),
transactions_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
uncles_hash: hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").into(),
extra_data: vec![],
state_root: hex!("d6368925ffd9acad81f411ce45891d3722e14355af2790391839488e23d74b0d").into(),
receipts_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
log_bloom: Default::default(),
gas_used: Default::default(),
gas_limit: 0x222222.into(),
difficulty: 0x20000.into(),
seal: vec![vec![0x80].into(), {
let mut vec = vec![0xb8, 0x41];
vec.resize(67, 0);
vec.into()
}],
}
}
/// Rialto headers pruning strategy.
///
/// We do not prune unfinalized headers because exchange module only accepts
/// claims from finalized headers. And if we're pruning unfinalized headers, then
/// some claims may never be accepted.
#[derive(Default, RuntimeDebug)]
pub struct PruningStrategy;
impl TPruningStrategy for PruningStrategy {
fn pruning_upper_bound(&mut self, _best_number: u64, best_finalized_number: u64) -> u64 {
best_finalized_number
.checked_sub(FINALIZED_HEADERS_TO_KEEP)
.unwrap_or(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn genesis_hash_matches() {
assert_eq!(
genesis_header().compute_hash(),
hex!("bc936e808b668546250ad43de5c0a95fe2a9644a850a2ff69b57f874e3e35644").into(),
);
}
#[test]
fn pruning_strategy_keeps_enough_headers() {
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 1_000),
0,
"1_000 <= 5_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 5_000),
0,
"5_000 <= 5_000 => nothing should be pruned yet",
);
assert_eq!(
PruningStrategy::default().pruning_upper_bound(100_000, 10_000),
5_000,
"5_000 <= 10_000 => we're ready to prune first 5_000 headers",
);
}
}
+5
View File
@@ -53,6 +53,10 @@ subcommands:
value_name: ETH_CONTRACT
help: Address of deployed bridge contract.
takes_value: true
- eth-chain-id: &eth-chain-id
long: eth-chain-id
value_name: ETH_CHAIN_ID
help: Chain ID to use for signing.
- eth-signer: &eth-signer
long: eth-signer
value_name: ETH_SIGNER
@@ -65,6 +69,7 @@ subcommands:
- eth-host: *eth-host
- eth-port: *eth-port
- eth-signer: *eth-signer
- eth-chain-id: *eth-chain-id
- eth-contract-code:
long: eth-contract-code
value_name: ETH_CONTRACT_CODE
@@ -51,7 +51,7 @@ const MAX_SUBMITTED_HEADERS: usize = 128;
const PRUNE_DEPTH: u32 = 4096;
/// Ethereum synchronization parameters.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct EthereumSyncParams {
/// Ethereum connection params.
pub eth: EthereumConnectionParams,
+14
View File
@@ -49,6 +49,7 @@ fn main() {
let matches = clap::App::from_yaml(yaml).get_matches();
match matches.subcommand() {
("eth-to-sub", Some(eth_to_sub_matches)) => {
log::info!(target: "bridge", "Starting ETH ➡ SUB relay.");
if ethereum_sync_loop::run(match ethereum_sync_params(&eth_to_sub_matches) {
Ok(ethereum_sync_params) => ethereum_sync_params,
Err(err) => {
@@ -63,6 +64,7 @@ fn main() {
};
}
("sub-to-eth", Some(sub_to_eth_matches)) => {
log::info!(target: "bridge", "Starting SUB ➡ ETH relay.");
if substrate_sync_loop::run(match substrate_sync_params(&sub_to_eth_matches) {
Ok(substrate_sync_params) => substrate_sync_params,
Err(err) => {
@@ -77,6 +79,7 @@ fn main() {
};
}
("eth-deploy-contract", Some(eth_deploy_matches)) => {
log::info!(target: "bridge", "Deploying ETH contracts.");
ethereum_deploy_contract::run(match ethereum_deploy_contract_params(&eth_deploy_matches) {
Ok(ethereum_deploy_matches) => ethereum_deploy_matches,
Err(err) => {
@@ -160,6 +163,11 @@ fn ethereum_signing_params(matches: &clap::ArgMatches) -> Result<EthereumSigning
.map_err(|e| format!("Failed to parse eth-signer: {}", e))
.and_then(|secret| KeyPair::from_secret(secret).map_err(|e| format!("Invalid eth-signer: {}", e)))?;
}
if let Some(eth_chain_id) = matches.value_of("eth-chain-id") {
params.chain_id = eth_chain_id
.parse::<u64>()
.map_err(|e| format!("Failed to parse eth-chain-id: {}", e))?;
}
Ok(params)
}
@@ -205,6 +213,8 @@ fn ethereum_sync_params(matches: &clap::ArgMatches) -> Result<EthereumSyncParams
None => eth_sync_params.sync_params.target_tx_mode = sync::TargetTransactionMode::Signed,
}
log::debug!(target: "bridge", "Ethereum sync params: {:?}", eth_sync_params);
Ok(eth_sync_params)
}
@@ -218,6 +228,8 @@ fn substrate_sync_params(matches: &clap::ArgMatches) -> Result<SubstrateSyncPara
sub_sync_params.eth_contract_address = eth_contract.parse().map_err(|e| format!("{}", e))?;
}
log::debug!(target: "bridge", "Substrate sync params: {:?}", sub_sync_params);
Ok(sub_sync_params)
}
@@ -234,6 +246,8 @@ fn ethereum_deploy_contract_params(
hex::decode(&eth_contract_code).map_err(|e| format!("Failed to parse eth-contract-code: {}", e))?;
}
log::debug!(target: "bridge", "Deploy params: {:?}", eth_deploy_params);
Ok(eth_deploy_params)
}