Support Pallet Instances in Relay (#238)

* Sketch out how to support different bridge pallet instances

* Create a common interface for using pallet instances

* Start introducing generic instance parameter

Attemps to make the compiler happy, but I'm having second thoughts about
this approach. Commiting now as a way to have a checkpoint, but I think
I'm going to need to re-consider my approach here.

Ideally I want a change which introduces minimal changes, but this seems
to be propagating around the codebase in ways I don't want.

* Use trait objects instead of generics

* Implement traits for Boxed trait objects

This is done in order to statisfy trait bounds by types
which use these new trait objects

* Remove Clone usage for sync parameters

* Remove implementation of Default for sync params

* Require that BridgeInstance implements Debug

* Ensure that BridgeInstance trait implements Send/Sync

* Add documentation related to instances

* Rust Fmt

* Remove needless format

* Make instance CLI option case insensitive

* Replace `with_*` constructors with `new`

* Clean up usage of instance structs

* Enforce a default instance in the CLI params

* Build sync params as we process input from CLI

* Remove case insensitivity from sub-tx-mode

I think this should happen, but maybe as part of a different PR

* Process default Eth contract deployment config in CLI

* Build EthereumExchangeParams in CLI

* Process EthereumExchangeSubmitParams params in CLI
This commit is contained in:
Hernando Castano
2020-08-04 12:03:21 -04:00
committed by Bastian Köcher
parent 6fd1651b21
commit 7f8360d8ab
10 changed files with 467 additions and 286 deletions
@@ -20,6 +20,7 @@ use crate::ethereum_client::{
EthereumConnectionParams, EthereumHighLevelRpc, EthereumRpcClient, EthereumSigningParams,
};
use crate::ethereum_types::Address;
use crate::instances::BridgeInstance;
use crate::metrics::MetricsParams;
use crate::rpc::SubstrateRpc;
use crate::rpc_errors::RpcError;
@@ -27,66 +28,47 @@ use crate::substrate_client::{SubstrateConnectionParams, SubstrateRpcClient};
use crate::substrate_types::{
GrandpaJustification, Hash, Header, Number, QueuedSubstrateHeader, SubstrateHeaderId, SubstrateHeadersSyncPipeline,
};
use crate::sync::{HeadersSyncParams, TargetTransactionMode};
use crate::sync::HeadersSyncParams;
use crate::sync_loop::{SourceClient, TargetClient};
use crate::sync_types::{SourceHeader, SubmittedHeaders};
use async_trait::async_trait;
use std::fmt::Debug;
use std::{collections::HashSet, time::Duration};
/// Interval at which we check new Substrate headers when we are synced/almost synced.
const SUBSTRATE_TICK_INTERVAL: Duration = Duration::from_secs(10);
/// Interval at which we check new Ethereum blocks.
const ETHEREUM_TICK_INTERVAL: Duration = Duration::from_secs(5);
/// Max Ethereum headers we want to have in all 'before-submitted' states.
const MAX_FUTURE_HEADERS_TO_DOWNLOAD: usize = 8;
/// Max Ethereum headers count we want to have in 'submitted' state.
const MAX_SUBMITTED_HEADERS: usize = 1;
/// Max depth of in-memory headers in all states. Past this depth they will be forgotten (pruned).
const PRUNE_DEPTH: u32 = 256;
pub mod consts {
use super::*;
/// Interval at which we check new Substrate headers when we are synced/almost synced.
pub const SUBSTRATE_TICK_INTERVAL: Duration = Duration::from_secs(10);
/// Interval at which we check new Ethereum blocks.
pub const ETHEREUM_TICK_INTERVAL: Duration = Duration::from_secs(5);
/// Max Ethereum headers we want to have in all 'before-submitted' states.
pub const MAX_FUTURE_HEADERS_TO_DOWNLOAD: usize = 8;
/// Max Ethereum headers count we want to have in 'submitted' state.
pub const MAX_SUBMITTED_HEADERS: usize = 1;
/// Max depth of in-memory headers in all states. Past this depth they will be forgotten (pruned).
pub const PRUNE_DEPTH: u32 = 256;
}
/// Substrate synchronization parameters.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct SubstrateSyncParams {
/// Substrate connection params.
pub sub_params: SubstrateConnectionParams,
/// Ethereum connection params.
pub eth: EthereumConnectionParams,
pub eth_params: EthereumConnectionParams,
/// Ethereum signing params.
pub eth_sign: EthereumSigningParams,
/// Ethereum bridge contract address.
pub eth_contract_address: Address,
/// Substrate connection params.
pub sub: SubstrateConnectionParams,
/// Synchronization parameters.
pub sync_params: HeadersSyncParams,
/// Metrics parameters.
pub metrics_params: Option<MetricsParams>,
}
impl Default for SubstrateSyncParams {
fn default() -> Self {
SubstrateSyncParams {
eth: Default::default(),
eth_sign: Default::default(),
// the address 0x731a10897d267e19b34503ad902d0a29173ba4b1 is the address
// of the contract that is deployed by default signer and 0 nonce
eth_contract_address: "731a10897d267e19b34503ad902d0a29173ba4b1"
.parse()
.expect("address is hardcoded, thus valid; qed"),
sub: Default::default(),
sync_params: HeadersSyncParams {
max_future_headers_to_download: MAX_FUTURE_HEADERS_TO_DOWNLOAD,
max_headers_in_submitted_status: MAX_SUBMITTED_HEADERS,
// since we always have single Substrate header in separate Ethereum transaction,
// all max_**_in_single_submit aren't important here
max_headers_in_single_submit: 4,
max_headers_size_in_single_submit: std::usize::MAX,
prune_depth: PRUNE_DEPTH,
target_tx_mode: TargetTransactionMode::Signed,
},
metrics_params: Some(Default::default()),
}
}
/// Instance of the bridge pallet being synchronized.
pub instance: Box<dyn BridgeInstance>,
}
/// Substrate client as headers source.
@@ -199,21 +181,29 @@ impl TargetClient<SubstrateHeadersSyncPipeline> for EthereumHeadersTarget {
/// Run Substrate headers synchronization.
pub fn run(params: SubstrateSyncParams) -> Result<(), RpcError> {
let sub_params = params.clone();
let SubstrateSyncParams {
sub_params,
eth_params,
eth_sign,
eth_contract_address,
sync_params,
metrics_params,
instance,
} = params;
let eth_client = EthereumRpcClient::new(params.eth);
let sub_client = async_std::task::block_on(async { SubstrateRpcClient::new(sub_params.sub).await })?;
let eth_client = EthereumRpcClient::new(eth_params);
let sub_client = async_std::task::block_on(async { SubstrateRpcClient::new(sub_params, instance).await })?;
let target = EthereumHeadersTarget::new(eth_client, params.eth_contract_address, params.eth_sign);
let target = EthereumHeadersTarget::new(eth_client, eth_contract_address, eth_sign);
let source = SubstrateHeadersSource::new(sub_client);
crate::sync_loop::run(
source,
SUBSTRATE_TICK_INTERVAL,
consts::SUBSTRATE_TICK_INTERVAL,
target,
ETHEREUM_TICK_INTERVAL,
params.sync_params,
params.metrics_params,
consts::ETHEREUM_TICK_INTERVAL,
sync_params,
metrics_params,
futures::future::pending(),
);