Skip to content

Commit

Permalink
Support Pallet Instances in Relay (paritytech#238)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
HCastano authored and bkchr committed Apr 10, 2024
1 parent 6fd1651 commit 7f8360d
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 280 deletions.
11 changes: 11 additions & 0 deletions bridges/relays/ethereum/src/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ subcommands:
long: sub-signer-password
value_name: SUB_SIGNER_PASSWORD
help: The password for the SURI of secret key to use when transactions are submitted to the Substrate node.
- sub-pallet-instance: &sub-pallet-instance
long: instance
short: i
value_name: PALLET_INSTANCE
help: The instance of the bridge pallet the relay should follow.
takes_value: true
case_insensitive: true
possible_values:
- Rialto
- Kovan
default_value: Rialto
- no-prometheus: &no-prometheus
long: no-prometheus
help: Do not expose a Prometheus metric endpoint.
Expand Down
47 changes: 23 additions & 24 deletions bridges/relays/ethereum/src/ethereum_deploy_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use crate::ethereum_client::{
bridge_contract, EthereumConnectionParams, EthereumHighLevelRpc, EthereumRpcClient, EthereumSigningParams,
};
use crate::instances::BridgeInstance;
use crate::rpc::SubstrateRpc;
use crate::substrate_client::{SubstrateConnectionParams, SubstrateRpcClient};
use crate::substrate_types::{Hash as SubstrateHash, Header as SubstrateHeader, SubstrateHeaderId};
Expand All @@ -29,50 +30,48 @@ use num_traits::Zero;
#[derive(Debug)]
pub struct EthereumDeployContractParams {
/// Ethereum connection params.
pub eth: EthereumConnectionParams,
pub eth_params: EthereumConnectionParams,
/// Ethereum signing params.
pub eth_sign: EthereumSigningParams,
/// Ethereum contract bytecode.
pub eth_contract_code: Vec<u8>,
/// Substrate connection params.
pub sub: SubstrateConnectionParams,
pub sub_params: SubstrateConnectionParams,
/// Initial authorities set id.
pub sub_initial_authorities_set_id: Option<u64>,
/// Initial authorities set.
pub sub_initial_authorities_set: Option<Vec<u8>>,
/// Initial header.
pub sub_initial_header: Option<Vec<u8>>,
}

impl Default for EthereumDeployContractParams {
fn default() -> Self {
EthereumDeployContractParams {
eth: Default::default(),
eth_sign: Default::default(),
eth_contract_code: hex::decode(include_str!("../res/substrate-bridge-bytecode.hex"))
.expect("code is hardcoded, thus valid; qed"),
sub: Default::default(),
sub_initial_authorities_set_id: None,
sub_initial_authorities_set: None,
sub_initial_header: None,
}
}
/// Instance of the bridge pallet being synchronized.
pub instance: Box<dyn BridgeInstance>,
}

/// Deploy Bridge contract on Ethereum chain.
pub fn run(params: EthereumDeployContractParams) {
let mut local_pool = futures::executor::LocalPool::new();

let EthereumDeployContractParams {
eth_params,
eth_sign,
sub_params,
instance,
sub_initial_authorities_set_id,
sub_initial_authorities_set,
sub_initial_header,
eth_contract_code,
} = params;

let result = local_pool.run_until(async move {
let eth_client = EthereumRpcClient::new(params.eth);
let sub_client = SubstrateRpcClient::new(params.sub).await?;
let eth_client = EthereumRpcClient::new(eth_params);
let sub_client = SubstrateRpcClient::new(sub_params, instance).await?;

let (initial_header_id, initial_header) = prepare_initial_header(&sub_client, params.sub_initial_header).await?;
let initial_set_id = params.sub_initial_authorities_set_id.unwrap_or(0);
let (initial_header_id, initial_header) = prepare_initial_header(&sub_client, sub_initial_header).await?;
let initial_set_id = sub_initial_authorities_set_id.unwrap_or(0);
let initial_set = prepare_initial_authorities_set(
&sub_client,
initial_header_id.1,
params.sub_initial_authorities_set,
sub_initial_authorities_set,
).await?;

log::info!(
Expand All @@ -87,8 +86,8 @@ pub fn run(params: EthereumDeployContractParams) {

deploy_bridge_contract(
&eth_client,
&params.eth_sign,
params.eth_contract_code,
&eth_sign,
eth_contract_code,
initial_header,
initial_set_id,
initial_set,
Expand Down
50 changes: 29 additions & 21 deletions bridges/relays/ethereum/src/ethereum_exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::exchange::{
TransactionProofPipeline,
};
use crate::exchange_loop::{run as run_loop, InMemoryStorage};
use crate::instances::BridgeInstance;
use crate::metrics::MetricsParams;
use crate::rpc::{EthereumRpc, SubstrateRpc};
use crate::rpc_errors::RpcError;
Expand Down Expand Up @@ -58,15 +59,17 @@ pub enum ExchangeRelayMode {
#[derive(Debug)]
pub struct EthereumExchangeParams {
/// Ethereum connection params.
pub eth: EthereumConnectionParams,
pub eth_params: EthereumConnectionParams,
/// Substrate connection params.
pub sub: SubstrateConnectionParams,
pub sub_params: SubstrateConnectionParams,
/// Substrate signing params.
pub sub_sign: SubstrateSigningParams,
/// Relay working mode.
pub mode: ExchangeRelayMode,
/// Metrics parameters.
pub metrics_params: Option<MetricsParams>,
/// Instance of the bridge pallet being synchronized.
pub instance: Box<dyn BridgeInstance>,
}

/// Ethereum to Substrate exchange pipeline.
Expand Down Expand Up @@ -253,18 +256,6 @@ impl TargetClient<EthereumToSubstrateExchange> for SubstrateTransactionsTarget {
}
}

impl Default for EthereumExchangeParams {
fn default() -> Self {
EthereumExchangeParams {
eth: Default::default(),
sub: Default::default(),
sub_sign: Default::default(),
mode: ExchangeRelayMode::Auto(None),
metrics_params: Some(Default::default()),
}
}
}

/// Relay exchange transaction proof(s) to Substrate node.
pub fn run(params: EthereumExchangeParams) {
match params.mode {
Expand All @@ -279,14 +270,22 @@ pub fn run(params: EthereumExchangeParams) {
fn run_single_transaction_relay(params: EthereumExchangeParams, eth_tx_hash: H256) {
let mut local_pool = futures::executor::LocalPool::new();

let EthereumExchangeParams {
eth_params,
sub_params,
sub_sign,
instance,
..
} = params;

let result = local_pool.run_until(async move {
let eth_client = EthereumRpcClient::new(params.eth);
let sub_client = SubstrateRpcClient::new(params.sub).await?;
let eth_client = EthereumRpcClient::new(eth_params);
let sub_client = SubstrateRpcClient::new(sub_params, instance).await?;

let source = EthereumTransactionsSource { client: eth_client };
let target = SubstrateTransactionsTarget {
client: sub_client,
sign_params: params.sub_sign,
sign_params: sub_sign,
};

relay_single_transaction_proof(&source, &target, eth_tx_hash).await
Expand All @@ -313,9 +312,18 @@ fn run_single_transaction_relay(params: EthereumExchangeParams, eth_tx_hash: H25

/// Run auto-relay loop.
fn run_auto_transactions_relay_loop(params: EthereumExchangeParams, eth_start_with_block_number: Option<u64>) {
let EthereumExchangeParams {
eth_params,
sub_params,
sub_sign,
metrics_params,
instance,
..
} = params;

let do_run_loop = move || -> Result<(), String> {
let eth_client = EthereumRpcClient::new(params.eth);
let sub_client = async_std::task::block_on(SubstrateRpcClient::new(params.sub))
let eth_client = EthereumRpcClient::new(eth_params);
let sub_client = async_std::task::block_on(SubstrateRpcClient::new(sub_params, instance))
.map_err(|err| format!("Error starting Substrate client: {:?}", err))?;

let eth_start_with_block_number = match eth_start_with_block_number {
Expand All @@ -337,9 +345,9 @@ fn run_auto_transactions_relay_loop(params: EthereumExchangeParams, eth_start_wi
EthereumTransactionsSource { client: eth_client },
SubstrateTransactionsTarget {
client: sub_client,
sign_params: params.sub_sign,
sign_params: sub_sign,
},
params.metrics_params,
metrics_params,
futures::future::pending(),
);

Expand Down
41 changes: 18 additions & 23 deletions bridges/relays/ethereum/src/ethereum_exchange_submit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::ethereum_types::{CallRequest, U256};
use crate::rpc::EthereumRpc;

use bridge_node_runtime::exchange::LOCK_FUNDS_ADDRESS;
use hex_literal::hex;
use sp_bridge_eth_poa::{
signatures::{SecretKey, SignTransaction},
UnsignedTransaction,
Expand All @@ -31,7 +30,7 @@ use sp_bridge_eth_poa::{
#[derive(Debug)]
pub struct EthereumExchangeSubmitParams {
/// Ethereum connection params.
pub eth: EthereumConnectionParams,
pub eth_params: EthereumConnectionParams,
/// Ethereum signing params.
pub eth_sign: EthereumSigningParams,
/// Ethereum signer nonce.
Expand All @@ -42,28 +41,24 @@ pub struct EthereumExchangeSubmitParams {
pub sub_recipient: [u8; 32],
}

impl Default for EthereumExchangeSubmitParams {
fn default() -> Self {
EthereumExchangeSubmitParams {
eth: Default::default(),
eth_sign: Default::default(),
eth_nonce: None,
eth_amount: 1_000_000_000_000_000_000_u64.into(), // 1 ETH
sub_recipient: hex!("1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c"), // ferdie
}
}
}

/// Submit single Ethereum -> Substrate exchange transaction.
pub fn run(params: EthereumExchangeSubmitParams) {
let mut local_pool = futures::executor::LocalPool::new();

let EthereumExchangeSubmitParams {
eth_params,
eth_sign,
eth_nonce,
eth_amount,
sub_recipient,
} = params;

let result: Result<_, String> = local_pool.run_until(async move {
let eth_client = EthereumRpcClient::new(params.eth);
let eth_client = EthereumRpcClient::new(eth_params);

let eth_signer_address = params.eth_sign.signer.address();
let sub_recipient_encoded = params.sub_recipient;
let nonce = match params.eth_nonce {
let eth_signer_address = eth_sign.signer.address();
let sub_recipient_encoded = sub_recipient;
let nonce = match eth_nonce {
Some(eth_nonce) => eth_nonce,
None => eth_client
.account_nonce(eth_signer_address)
Expand All @@ -74,24 +69,24 @@ pub fn run(params: EthereumExchangeSubmitParams) {
.estimate_gas(CallRequest {
from: Some(eth_signer_address),
to: Some(LOCK_FUNDS_ADDRESS.into()),
value: Some(params.eth_amount),
value: Some(eth_amount),
data: Some(sub_recipient_encoded.to_vec().into()),
..Default::default()
})
.await
.map_err(|err| format!("error estimating gas requirements: {:?}", err))?;
let eth_tx_unsigned = UnsignedTransaction {
nonce,
gas_price: params.eth_sign.gas_price,
gas_price: eth_sign.gas_price,
gas,
to: Some(LOCK_FUNDS_ADDRESS.into()),
value: params.eth_amount,
value: eth_amount,
payload: sub_recipient_encoded.to_vec(),
};
let eth_tx_signed = eth_tx_unsigned.clone().sign_by(
&SecretKey::parse(params.eth_sign.signer.secret().as_fixed_bytes())
&SecretKey::parse(eth_sign.signer.secret().as_fixed_bytes())
.expect("key is accepted by secp256k1::KeyPair and thus is valid; qed"),
Some(params.eth_sign.chain_id),
Some(eth_sign.chain_id),
);
eth_client
.submit_transaction(eth_tx_signed)
Expand Down
Loading

0 comments on commit 7f8360d

Please # to comment.