// Copyright 2019-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 .
//! Relaying proofs of PoA -> Substrate exchange transactions.
use crate::instances::BridgeInstance;
use crate::rialto_client::{SubmitEthereumExchangeTransactionProof, SubstrateHighLevelRpc};
use crate::rpc_errors::RpcError;
use crate::substrate_types::into_substrate_ethereum_receipt;
use async_trait::async_trait;
use bp_currency_exchange::MaybeLockFundsTransaction;
use exchange_relay::exchange::{
relay_single_transaction_proof, SourceBlock, SourceClient, SourceTransaction, TargetClient,
TransactionProofPipeline,
};
use exchange_relay::exchange_loop::{run as run_loop, InMemoryStorage};
use relay_ethereum_client::{
types::{
HeaderId as EthereumHeaderId, HeaderWithTransactions as EthereumHeaderWithTransactions,
Transaction as EthereumTransaction, TransactionHash as EthereumTransactionHash, H256, HEADER_ID_PROOF,
},
Client as EthereumClient, ConnectionParams as EthereumConnectionParams,
};
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
use relay_substrate_client::{
Chain as SubstrateChain, Client as SubstrateClient, ConnectionParams as SubstrateConnectionParams,
};
use relay_utils::{metrics::MetricsParams, HeaderId};
use rialto_runtime::exchange::EthereumTransactionInclusionProof;
use std::{sync::Arc, time::Duration};
/// Interval at which we ask Ethereum node for updates.
const ETHEREUM_TICK_INTERVAL: Duration = Duration::from_secs(10);
/// Exchange relay mode.
#[derive(Debug)]
pub enum ExchangeRelayMode {
/// Relay single transaction and quit.
Single(EthereumTransactionHash),
/// Auto-relay transactions starting with given block.
Auto(Option),
}
/// PoA exchange transaction relay params.
#[derive(Debug)]
pub struct EthereumExchangeParams {
/// Ethereum connection params.
pub eth_params: EthereumConnectionParams,
/// Substrate connection params.
pub sub_params: SubstrateConnectionParams,
/// Substrate signing params.
pub sub_sign: RialtoSigningParams,
/// Relay working mode.
pub mode: ExchangeRelayMode,
/// Metrics parameters.
pub metrics_params: Option,
/// Instance of the bridge pallet being synchronized.
pub instance: Arc,
}
/// Ethereum to Substrate exchange pipeline.
struct EthereumToSubstrateExchange;
impl TransactionProofPipeline for EthereumToSubstrateExchange {
const SOURCE_NAME: &'static str = "Ethereum";
const TARGET_NAME: &'static str = "Substrate";
type Block = EthereumSourceBlock;
type TransactionProof = EthereumTransactionInclusionProof;
}
/// Ethereum source block.
struct EthereumSourceBlock(EthereumHeaderWithTransactions);
impl SourceBlock for EthereumSourceBlock {
type Hash = H256;
type Number = u64;
type Transaction = EthereumSourceTransaction;
fn id(&self) -> EthereumHeaderId {
HeaderId(
self.0.number.expect(HEADER_ID_PROOF).as_u64(),
self.0.hash.expect(HEADER_ID_PROOF),
)
}
fn transactions(&self) -> Vec {
self.0
.transactions
.iter()
.cloned()
.map(EthereumSourceTransaction)
.collect()
}
}
/// Ethereum source transaction.
struct EthereumSourceTransaction(EthereumTransaction);
impl SourceTransaction for EthereumSourceTransaction {
type Hash = EthereumTransactionHash;
fn hash(&self) -> Self::Hash {
self.0.hash
}
}
/// Ethereum node as transactions proof source.
struct EthereumTransactionsSource {
client: EthereumClient,
}
#[async_trait]
impl SourceClient for EthereumTransactionsSource {
type Error = RpcError;
async fn tick(&self) {
async_std::task::sleep(ETHEREUM_TICK_INTERVAL).await;
}
async fn block_by_hash(&self, hash: H256) -> Result {
self.client
.header_by_hash_with_transactions(hash)
.await
.map(EthereumSourceBlock)
.map_err(Into::into)
}
async fn block_by_number(&self, number: u64) -> Result {
self.client
.header_by_number_with_transactions(number)
.await
.map(EthereumSourceBlock)
.map_err(Into::into)
}
async fn transaction_block(
&self,
hash: &EthereumTransactionHash,
) -> Result