Extract minimal ethereum client (#359)

* relay-ethereum-client

* use relay-ethereum-client from ethereum-poa-relay

* cargo fmt --all

* #![warn(missing_docs)]

* EthereumRpcClient -> EthereumClient

* make EthereumHeadersSyncPipeline private

* return concrete type from crate::new

* cleanup dependencies

* *self -> self

* remove trait Client

* sort deps
This commit is contained in:
Svyatoslav Nikolsky
2020-09-22 11:43:04 +03:00
committed by Bastian Köcher
parent d614cdaba8
commit ec34870eab
20 changed files with 556 additions and 384 deletions
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "relay-ethereum-client"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
[dependencies]
codec = { package = "parity-scale-codec", version = "1.3.4" }
ethereum-tx-sign = "3.0"
headers-relay = { path = "../headers-relay" }
hex = "0.4"
jsonrpsee = { git = "https://github.com/svyatonik/jsonrpsee.git", branch = "shared-client-in-rpc-api", default-features = false, features = ["http"] }
log = "0.4.11"
parity-crypto = { version = "0.6", features = ["publickey"] }
relay-utils = { path = "../utils" }
web3 = "0.13"
@@ -0,0 +1,142 @@
// 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 <http://www.gnu.org/licenses/>.
use crate::rpc::Ethereum;
use crate::types::{
Address, Bytes, CallRequest, Header, HeaderWithTransactions, Receipt, SignedRawTx, Transaction, TransactionHash,
H256, U256,
};
use crate::{ConnectionParams, Error, Result};
use jsonrpsee::raw::RawClient;
use jsonrpsee::transport::http::HttpTransportClient;
use jsonrpsee::Client as RpcClient;
/// The client used to interact with an Ethereum node through RPC.
#[derive(Clone)]
pub struct Client {
client: RpcClient,
}
impl Client {
/// Create a new Ethereum RPC Client.
pub fn new(params: ConnectionParams) -> Self {
let uri = format!("http://{}:{}", params.host, params.port);
let transport = HttpTransportClient::new(&uri);
let raw_client = RawClient::new(transport);
let client: RpcClient = raw_client.into();
Self { client }
}
}
impl Client {
/// Estimate gas usage for the given call.
pub async fn estimate_gas(&self, call_request: CallRequest) -> Result<U256> {
Ok(Ethereum::estimate_gas(&self.client, call_request).await?)
}
/// Retrieve number of the best known block from the Ethereum node.
pub async fn best_block_number(&self) -> Result<u64> {
Ok(Ethereum::block_number(&self.client).await?.as_u64())
}
/// Retrieve number of the best known block from the Ethereum node.
pub async fn header_by_number(&self, block_number: u64) -> Result<Header> {
let get_full_tx_objects = false;
let header = Ethereum::get_block_by_number(&self.client, block_number, get_full_tx_objects).await?;
match header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some() {
true => Ok(header),
false => Err(Error::IncompleteHeader),
}
}
/// Retrieve block header by its hash from Ethereum node.
pub async fn header_by_hash(&self, hash: H256) -> Result<Header> {
let get_full_tx_objects = false;
let header = Ethereum::get_block_by_hash(&self.client, hash, get_full_tx_objects).await?;
match header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some() {
true => Ok(header),
false => Err(Error::IncompleteHeader),
}
}
/// Retrieve block header and its transactions by its number from Ethereum node.
pub async fn header_by_number_with_transactions(&self, number: u64) -> Result<HeaderWithTransactions> {
let get_full_tx_objects = true;
let header = Ethereum::get_block_by_number_with_transactions(&self.client, number, get_full_tx_objects).await?;
let is_complete_header = header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some();
if !is_complete_header {
return Err(Error::IncompleteHeader);
}
let is_complete_transactions = header.transactions.iter().all(|tx| tx.raw.is_some());
if !is_complete_transactions {
return Err(Error::IncompleteTransaction);
}
Ok(header)
}
/// Retrieve block header and its transactions by its hash from Ethereum node.
pub async fn header_by_hash_with_transactions(&self, hash: H256) -> Result<HeaderWithTransactions> {
let get_full_tx_objects = true;
let header = Ethereum::get_block_by_hash_with_transactions(&self.client, hash, get_full_tx_objects).await?;
let is_complete_header = header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some();
if !is_complete_header {
return Err(Error::IncompleteHeader);
}
let is_complete_transactions = header.transactions.iter().all(|tx| tx.raw.is_some());
if !is_complete_transactions {
return Err(Error::IncompleteTransaction);
}
Ok(header)
}
/// Retrieve transaction by its hash from Ethereum node.
pub async fn transaction_by_hash(&self, hash: H256) -> Result<Option<Transaction>> {
Ok(Ethereum::transaction_by_hash(&self.client, hash).await?)
}
/// Retrieve transaction receipt by transaction hash.
pub async fn transaction_receipt(&self, transaction_hash: H256) -> Result<Receipt> {
Ok(Ethereum::get_transaction_receipt(&self.client, transaction_hash).await?)
}
/// Get the nonce of the given account.
pub async fn account_nonce(&self, address: Address) -> Result<U256> {
Ok(Ethereum::get_transaction_count(&self.client, address).await?)
}
/// Submit an Ethereum transaction.
///
/// The transaction must already be signed before sending it through this method.
pub async fn submit_transaction(&self, signed_raw_tx: SignedRawTx) -> Result<TransactionHash> {
let transaction = Bytes(signed_raw_tx);
let tx_hash = Ethereum::submit_transaction(&self.client, transaction).await?;
log::trace!(target: "bridge", "Sent transaction to Ethereum node: {:?}", tx_hash);
Ok(tx_hash)
}
/// Call Ethereum smart contract.
pub async fn eth_call(&self, call_transaction: CallRequest) -> Result<Bytes> {
Ok(Ethereum::call(&self.client, call_transaction).await?)
}
}
@@ -0,0 +1,71 @@
// 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 <http://www.gnu.org/licenses/>.
//! Ethereum node RPC errors.
use jsonrpsee::client::RequestError;
use relay_utils::MaybeConnectionError;
/// Result type used by Ethereum client.
pub type Result<T> = std::result::Result<T, Error>;
/// Errors that can occur only when interacting with
/// an Ethereum node through RPC.
#[derive(Debug)]
pub enum Error {
/// An error that can occur when making an HTTP request to
/// an JSON-RPC client.
Request(RequestError),
/// Failed to parse response.
ResponseParseFailed(String),
/// We have received a header with missing fields.
IncompleteHeader,
/// We have received a transaction missing a `raw` field.
IncompleteTransaction,
/// An invalid Substrate block number was received from
/// an Ethereum node.
InvalidSubstrateBlockNumber,
/// An invalid index has been received from an Ethereum node.
InvalidIncompleteIndex,
}
impl From<RequestError> for Error {
fn from(error: RequestError) -> Self {
Error::Request(error)
}
}
impl MaybeConnectionError for Error {
fn is_connection_error(&self) -> bool {
matches!(*self, Error::Request(RequestError::TransportError(_)))
}
}
impl ToString for Error {
fn to_string(&self) -> String {
match self {
Self::Request(e) => e.to_string(),
Self::ResponseParseFailed(e) => e.to_string(),
Self::IncompleteHeader => {
"Incomplete Ethereum Header Received (missing some of required fields - hash, number, logs_bloom)"
.to_string()
}
Self::IncompleteTransaction => "Incomplete Ethereum Transaction (missing required field - raw)".to_string(),
Self::InvalidSubstrateBlockNumber => "Received an invalid Substrate block from Ethereum Node".to_string(),
Self::InvalidIncompleteIndex => "Received an invalid incomplete index from Ethereum Node".to_string(),
}
}
}
+48
View File
@@ -0,0 +1,48 @@
// 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 <http://www.gnu.org/licenses/>.
//! Tools to interact with (Open) Ethereum node using RPC methods.
#![warn(missing_docs)]
mod client;
mod error;
mod rpc;
mod sign;
pub use crate::client::Client;
pub use crate::error::{Error, Result};
pub use crate::sign::{sign_and_submit_transaction, SigningParams};
pub mod types;
/// Ethereum connection params.
#[derive(Debug, Clone)]
pub struct ConnectionParams {
/// Ethereum RPC host.
pub host: String,
/// Ethereum RPC port.
pub port: u16,
}
impl Default for ConnectionParams {
fn default() -> Self {
ConnectionParams {
host: "localhost".into(),
port: 8545,
}
}
}
+53
View File
@@ -0,0 +1,53 @@
// 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 <http://www.gnu.org/licenses/>.
//! Ethereum node RPC interface.
// The compiler doesn't think we're using the
// code from rpc_api!
#![allow(dead_code)]
#![allow(unused_variables)]
use crate::types::{
Address, Bytes, CallRequest, Header, HeaderWithTransactions, Receipt, Transaction, TransactionHash, H256, U256, U64,
};
jsonrpsee::rpc_api! {
pub(crate) Ethereum {
#[rpc(method = "eth_estimateGas", positional_params)]
fn estimate_gas(call_request: CallRequest) -> U256;
#[rpc(method = "eth_blockNumber", positional_params)]
fn block_number() -> U64;
#[rpc(method = "eth_getBlockByNumber", positional_params)]
fn get_block_by_number(block_number: U64, full_tx_objs: bool) -> Header;
#[rpc(method = "eth_getBlockByHash", positional_params)]
fn get_block_by_hash(hash: H256, full_tx_objs: bool) -> Header;
#[rpc(method = "eth_getBlockByNumber", positional_params)]
fn get_block_by_number_with_transactions(number: U64, full_tx_objs: bool) -> HeaderWithTransactions;
#[rpc(method = "eth_getBlockByHash", positional_params)]
fn get_block_by_hash_with_transactions(hash: H256, full_tx_objs: bool) -> HeaderWithTransactions;
#[rpc(method = "eth_getTransactionByHash", positional_params)]
fn transaction_by_hash(hash: H256) -> Option<Transaction>;
#[rpc(method = "eth_getTransactionReceipt", positional_params)]
fn get_transaction_receipt(transaction_hash: H256) -> Receipt;
#[rpc(method = "eth_getTransactionCount", positional_params)]
fn get_transaction_count(address: Address) -> U256;
#[rpc(method = "eth_submitTransaction", positional_params)]
fn submit_transaction(transaction: Bytes) -> TransactionHash;
#[rpc(method = "eth_call", positional_params)]
fn call(transaction_call: CallRequest) -> Bytes;
}
}
@@ -0,0 +1,85 @@
// 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 <http://www.gnu.org/licenses/>.
use crate::types::{Address, CallRequest, U256};
use crate::{Client, Result};
use parity_crypto::publickey::KeyPair;
/// Ethereum signing params.
#[derive(Clone, Debug)]
pub struct SigningParams {
/// Ethereum chain id.
pub chain_id: u64,
/// Ethereum transactions signer.
pub signer: KeyPair,
/// Gas price we agree to pay.
pub gas_price: U256,
}
impl Default for SigningParams {
fn default() -> Self {
SigningParams {
chain_id: 0x11, // Parity dev chain
// account that has a lot of ether when we run instant seal engine
// address: 0x00a329c0648769a73afac7f9381e08fb43dbea72
// secret: 0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7
signer: KeyPair::from_secret_slice(
&hex::decode("4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7")
.expect("secret is hardcoded, thus valid; qed"),
)
.expect("secret is hardcoded, thus valid; qed"),
gas_price: 8_000_000_000u64.into(), // 8 Gwei
}
}
}
/// Sign and submit tranaction using given Ethereum client.
pub async fn sign_and_submit_transaction(
client: &Client,
params: &SigningParams,
contract_address: Option<Address>,
nonce: Option<U256>,
double_gas: bool,
encoded_call: Vec<u8>,
) -> Result<()> {
let nonce = if let Some(n) = nonce {
n
} else {
let address: Address = params.signer.address().as_fixed_bytes().into();
client.account_nonce(address).await?
};
let call_request = CallRequest {
to: contract_address,
data: Some(encoded_call.clone().into()),
..Default::default()
};
let gas = client.estimate_gas(call_request).await?;
let raw_transaction = ethereum_tx_sign::RawTransaction {
nonce,
to: contract_address,
value: U256::zero(),
gas: if double_gas { gas.saturating_mul(2.into()) } else { gas },
gas_price: params.gas_price,
data: encoded_call,
}
.sign(&params.signer.secret().as_fixed_bytes().into(), &params.chain_id);
let _ = client.submit_transaction(raw_transaction).await?;
Ok(())
}
@@ -14,11 +14,9 @@
// 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 crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
//! Common types that are used in relay <-> Ethereum node communications.
use codec::Encode;
use headers_relay::sync_types::{HeadersSyncPipeline, QueuedHeader, SourceHeader};
use relay_utils::HeaderId;
use headers_relay::sync_types::SourceHeader;
pub use web3::types::{Address, Bytes, CallRequest, H256, U128, U256, U64};
@@ -26,6 +24,9 @@ pub use web3::types::{Address, Bytes, CallRequest, H256, U128, U256, U64};
/// both number and hash fields filled.
pub const HEADER_ID_PROOF: &str = "checked on retrieval; qed";
/// Ethereum transaction hash type.
pub type HeaderHash = H256;
/// Ethereum transaction hash type.
pub type TransactionHash = H256;
@@ -37,10 +38,11 @@ pub type Header = web3::types::Block<H256>;
/// Ethereum header type used in headers sync.
#[derive(Clone, Debug, PartialEq)]
pub struct EthereumSyncHeader(Header);
pub struct SyncHeader(Header);
impl std::ops::Deref for EthereumSyncHeader {
impl std::ops::Deref for SyncHeader {
type Target = Header;
fn deref(&self) -> &Self::Target {
&self.0
}
@@ -53,52 +55,26 @@ pub type HeaderWithTransactions = web3::types::Block<Transaction>;
pub type Receipt = web3::types::TransactionReceipt;
/// Ethereum header ID.
pub type EthereumHeaderId = HeaderId<H256, u64>;
/// Queued ethereum header ID.
pub type QueuedEthereumHeader = QueuedHeader<EthereumHeadersSyncPipeline>;
pub type HeaderId = relay_utils::HeaderId<H256, u64>;
/// A raw Ethereum transaction that's been signed.
pub type SignedRawTx = Vec<u8>;
/// Ethereum synchronization pipeline.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct EthereumHeadersSyncPipeline;
impl HeadersSyncPipeline for EthereumHeadersSyncPipeline {
const SOURCE_NAME: &'static str = "Ethereum";
const TARGET_NAME: &'static str = "Substrate";
type Hash = H256;
type Number = u64;
type Header = EthereumSyncHeader;
type Extra = Vec<Receipt>;
type Completion = ();
fn estimate_size(source: &QueuedHeader<Self>) -> usize {
into_substrate_ethereum_header(source.header()).encode().len()
+ into_substrate_ethereum_receipts(source.extra())
.map(|extra| extra.encode().len())
.unwrap_or(0)
}
}
impl From<Header> for EthereumSyncHeader {
impl From<Header> for SyncHeader {
fn from(header: Header) -> Self {
Self(header)
}
}
impl SourceHeader<H256, u64> for EthereumSyncHeader {
fn id(&self) -> EthereumHeaderId {
HeaderId(
impl SourceHeader<H256, u64> for SyncHeader {
fn id(&self) -> HeaderId {
relay_utils::HeaderId(
self.number.expect(HEADER_ID_PROOF).as_u64(),
self.hash.expect(HEADER_ID_PROOF),
)
}
fn parent_id(&self) -> EthereumHeaderId {
HeaderId(self.number.expect(HEADER_ID_PROOF).as_u64() - 1, self.parent_hash)
fn parent_id(&self) -> HeaderId {
relay_utils::HeaderId(self.number.expect(HEADER_ID_PROOF).as_u64() - 1, self.parent_hash)
}
}
+1 -2
View File
@@ -17,7 +17,6 @@ env_logger = "0.7.0"
ethabi = "12.0"
ethabi-contract = "11.0"
ethabi-derive = "12.0"
ethereum-tx-sign = "3.0"
exchange-relay = { path = "../exchange-relay" }
futures = "0.3.5"
headers-relay = { path = "../headers-relay" }
@@ -27,11 +26,11 @@ log = "0.4.11"
messages-relay = { path = "../messages-relay" }
num-traits = "0.2"
parity-crypto = { version = "0.6", features = ["publickey"] }
relay-ethereum-client = { path = "../ethereum-client" }
relay-utils = { path = "../utils" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.57"
time = "0.2"
web3 = "0.13"
[dependencies.jsonrpsee]
git = "https://github.com/svyatonik/jsonrpsee.git"
+14 -192
View File
@@ -14,22 +14,18 @@
// 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 crate::ethereum_types::{
Address, Bytes, CallRequest, EthereumHeaderId, Header, HeaderWithTransactions, Receipt, SignedRawTx, Transaction,
TransactionHash, H256, U256,
};
use crate::rpc::{Ethereum, EthereumRpc};
use crate::rpc_errors::{EthereumNodeError, RpcError};
use crate::rpc_errors::RpcError;
use crate::substrate_types::{GrandpaJustification, Hash as SubstrateHash, QueuedSubstrateHeader, SubstrateHeaderId};
use async_trait::async_trait;
use codec::{Decode, Encode};
use ethabi::FunctionOutputDecoder;
use headers_relay::sync_types::SubmittedHeaders;
use jsonrpsee::raw::RawClient;
use jsonrpsee::transport::http::HttpTransportClient;
use jsonrpsee::Client;
use parity_crypto::publickey::KeyPair;
use relay_ethereum_client::{
sign_and_submit_transaction,
types::{Address, CallRequest, HeaderId as EthereumHeaderId, Receipt, H256, U256},
Client as EthereumClient, Error as EthereumNodeError, SigningParams as EthereumSigningParams,
};
use relay_utils::{HeaderId, MaybeConnectionError};
use std::collections::HashSet;
@@ -38,159 +34,10 @@ ethabi_contract::use_contract!(bridge_contract, "res/substrate-bridge-abi.json")
type RpcResult<T> = std::result::Result<T, RpcError>;
/// Ethereum connection params.
#[derive(Debug, Clone)]
pub struct EthereumConnectionParams {
/// Ethereum RPC host.
pub host: String,
/// Ethereum RPC port.
pub port: u16,
}
impl Default for EthereumConnectionParams {
fn default() -> Self {
EthereumConnectionParams {
host: "localhost".into(),
port: 8545,
}
}
}
/// Ethereum signing params.
#[derive(Clone, Debug)]
pub struct EthereumSigningParams {
/// Ethereum chain id.
pub chain_id: u64,
/// Ethereum transactions signer.
pub signer: KeyPair,
/// Gas price we agree to pay.
pub gas_price: U256,
}
impl Default for EthereumSigningParams {
fn default() -> Self {
EthereumSigningParams {
chain_id: 0x11, // Parity dev chain
// account that has a lot of ether when we run instant seal engine
// address: 0x00a329c0648769a73afac7f9381e08fb43dbea72
// secret: 0x4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7
signer: KeyPair::from_secret_slice(
&hex::decode("4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7")
.expect("secret is hardcoded, thus valid; qed"),
)
.expect("secret is hardcoded, thus valid; qed"),
gas_price: 8_000_000_000u64.into(), // 8 Gwei
}
}
}
/// The client used to interact with an Ethereum node through RPC.
pub struct EthereumRpcClient {
client: Client,
}
impl EthereumRpcClient {
/// Create a new Ethereum RPC Client.
pub fn new(params: EthereumConnectionParams) -> Self {
let uri = format!("http://{}:{}", params.host, params.port);
let transport = HttpTransportClient::new(&uri);
let raw_client = RawClient::new(transport);
let client: Client = raw_client.into();
Self { client }
}
}
#[async_trait]
impl EthereumRpc for EthereumRpcClient {
async fn estimate_gas(&self, call_request: CallRequest) -> RpcResult<U256> {
Ok(Ethereum::estimate_gas(&self.client, call_request).await?)
}
async fn best_block_number(&self) -> RpcResult<u64> {
Ok(Ethereum::block_number(&self.client).await?.as_u64())
}
async fn header_by_number(&self, block_number: u64) -> RpcResult<Header> {
let get_full_tx_objects = false;
let header = Ethereum::get_block_by_number(&self.client, block_number, get_full_tx_objects).await?;
match header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some() {
true => Ok(header),
false => Err(RpcError::Ethereum(EthereumNodeError::IncompleteHeader)),
}
}
async fn header_by_hash(&self, hash: H256) -> RpcResult<Header> {
let get_full_tx_objects = false;
let header = Ethereum::get_block_by_hash(&self.client, hash, get_full_tx_objects).await?;
match header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some() {
true => Ok(header),
false => Err(RpcError::Ethereum(EthereumNodeError::IncompleteHeader)),
}
}
async fn header_by_number_with_transactions(&self, number: u64) -> RpcResult<HeaderWithTransactions> {
let get_full_tx_objects = true;
let header = Ethereum::get_block_by_number_with_transactions(&self.client, number, get_full_tx_objects).await?;
let is_complete_header = header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some();
if !is_complete_header {
return Err(RpcError::Ethereum(EthereumNodeError::IncompleteHeader));
}
let is_complete_transactions = header.transactions.iter().all(|tx| tx.raw.is_some());
if !is_complete_transactions {
return Err(RpcError::Ethereum(EthereumNodeError::IncompleteTransaction));
}
Ok(header)
}
async fn header_by_hash_with_transactions(&self, hash: H256) -> RpcResult<HeaderWithTransactions> {
let get_full_tx_objects = true;
let header = Ethereum::get_block_by_hash_with_transactions(&self.client, hash, get_full_tx_objects).await?;
let is_complete_header = header.number.is_some() && header.hash.is_some() && header.logs_bloom.is_some();
if !is_complete_header {
return Err(RpcError::Ethereum(EthereumNodeError::IncompleteHeader));
}
let is_complete_transactions = header.transactions.iter().all(|tx| tx.raw.is_some());
if !is_complete_transactions {
return Err(RpcError::Ethereum(EthereumNodeError::IncompleteTransaction));
}
Ok(header)
}
async fn transaction_by_hash(&self, hash: H256) -> RpcResult<Option<Transaction>> {
Ok(Ethereum::transaction_by_hash(&self.client, hash).await?)
}
async fn transaction_receipt(&self, transaction_hash: H256) -> RpcResult<Receipt> {
Ok(Ethereum::get_transaction_receipt(&self.client, transaction_hash).await?)
}
async fn account_nonce(&self, address: Address) -> RpcResult<U256> {
Ok(Ethereum::get_transaction_count(&self.client, address).await?)
}
async fn submit_transaction(&self, signed_raw_tx: SignedRawTx) -> RpcResult<TransactionHash> {
let transaction = Bytes(signed_raw_tx);
let tx_hash = Ethereum::submit_transaction(&self.client, transaction).await?;
log::trace!(target: "bridge", "Sent transaction to Ethereum node: {:?}", tx_hash);
Ok(tx_hash)
}
async fn eth_call(&self, call_transaction: CallRequest) -> RpcResult<Bytes> {
Ok(Ethereum::call(&self.client, call_transaction).await?)
}
}
/// A trait which contains methods that work by using multiple low-level RPCs, or more complicated
/// interactions involving, for example, an Ethereum contract.
#[async_trait]
pub trait EthereumHighLevelRpc: EthereumRpc {
pub trait EthereumHighLevelRpc {
/// Returns best Substrate block that PoA chain knows of.
async fn best_substrate_block(&self, contract_address: Address) -> RpcResult<SubstrateHeaderId>;
@@ -240,7 +87,7 @@ pub trait EthereumHighLevelRpc: EthereumRpc {
}
#[async_trait]
impl EthereumHighLevelRpc for EthereumRpcClient {
impl EthereumHighLevelRpc for EthereumClient {
async fn best_substrate_block(&self, contract_address: Address) -> RpcResult<SubstrateHeaderId> {
let (encoded_call, call_decoder) = bridge_contract::functions::best_known_header::call();
let call_request = CallRequest {
@@ -293,7 +140,7 @@ impl EthereumHighLevelRpc for EthereumRpcClient {
submitted: Vec::new(),
incomplete: Vec::new(),
rejected: headers.iter().rev().map(|header| header.id()).collect(),
fatal_error: Some(error),
fatal_error: Some(error.into()),
}
}
};
@@ -302,9 +149,7 @@ impl EthereumHighLevelRpc for EthereumRpcClient {
// cloning `jsonrpsee::Client` only clones reference to background threads
submit_substrate_headers(
EthereumHeadersSubmitter {
client: EthereumRpcClient {
client: self.client.clone(),
},
client: self.clone(),
params,
contract_address,
nonce,
@@ -369,32 +214,9 @@ impl EthereumHighLevelRpc for EthereumRpcClient {
double_gas: bool,
encoded_call: Vec<u8>,
) -> RpcResult<()> {
let nonce = if let Some(n) = nonce {
n
} else {
let address: Address = params.signer.address().as_fixed_bytes().into();
self.account_nonce(address).await?
};
let call_request = CallRequest {
to: contract_address,
data: Some(encoded_call.clone().into()),
..Default::default()
};
let gas = self.estimate_gas(call_request).await?;
let raw_transaction = ethereum_tx_sign::RawTransaction {
nonce,
to: contract_address,
value: U256::zero(),
gas: if double_gas { gas.saturating_mul(2.into()) } else { gas },
gas_price: params.gas_price,
data: encoded_call,
}
.sign(&params.signer.secret().as_fixed_bytes().into(), &params.chain_id);
let _ = self.submit_transaction(raw_transaction).await?;
Ok(())
sign_and_submit_transaction(self, params, contract_address, nonce, double_gas, encoded_call)
.await
.map_err(Into::into)
}
async fn transaction_receipts(
@@ -524,7 +346,7 @@ trait HeadersSubmitter {
/// Implementation of Substrate headers submitter that sends headers to running Ethereum node.
struct EthereumHeadersSubmitter {
client: EthereumRpcClient,
client: EthereumClient,
params: EthereumSigningParams,
contract_address: Address,
nonce: U256,
@@ -14,9 +14,7 @@
// 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 crate::ethereum_client::{
bridge_contract, EthereumConnectionParams, EthereumHighLevelRpc, EthereumRpcClient, EthereumSigningParams,
};
use crate::ethereum_client::{bridge_contract, EthereumHighLevelRpc};
use crate::instances::BridgeInstance;
use crate::rpc::SubstrateRpc;
use crate::substrate_client::{SubstrateConnectionParams, SubstrateRpcClient};
@@ -24,6 +22,9 @@ use crate::substrate_types::{Hash as SubstrateHash, Header as SubstrateHeader, S
use codec::{Decode, Encode};
use num_traits::Zero;
use relay_ethereum_client::{
Client as EthereumClient, ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams,
};
use relay_utils::HeaderId;
/// Ethereum synchronization parameters.
@@ -63,7 +64,7 @@ pub fn run(params: EthereumDeployContractParams) {
} = params;
let result = local_pool.run_until(async move {
let eth_client = EthereumRpcClient::new(eth_params);
let eth_client = EthereumClient::new(eth_params);
let sub_client = SubstrateRpcClient::new(sub_params, instance).await?;
let (initial_header_id, initial_header) = prepare_initial_header(&sub_client, sub_initial_header).await?;
@@ -137,7 +138,7 @@ async fn prepare_initial_authorities_set(
/// Deploy bridge contract to Ethereum chain.
async fn deploy_bridge_contract(
eth_client: &EthereumRpcClient,
eth_client: &EthereumClient,
params: &EthereumSigningParams,
contract_code: Vec<u8>,
initial_header: Vec<u8>,
@@ -16,13 +16,8 @@
//! Relaying proofs of PoA -> Substrate exchange transactions.
use crate::ethereum_client::{EthereumConnectionParams, EthereumRpcClient};
use crate::ethereum_types::{
EthereumHeaderId, HeaderWithTransactions as EthereumHeaderWithTransactions, Transaction as EthereumTransaction,
TransactionHash as EthereumTransactionHash, H256,
};
use crate::instances::BridgeInstance;
use crate::rpc::{EthereumRpc, SubstrateRpc};
use crate::rpc::SubstrateRpc;
use crate::rpc_errors::RpcError;
use crate::substrate_client::{
SubmitEthereumExchangeTransactionProof, SubstrateConnectionParams, SubstrateRpcClient, SubstrateSigningParams,
@@ -36,6 +31,13 @@ use exchange_relay::exchange::{
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_utils::{metrics::MetricsParams, HeaderId};
use rialto_runtime::exchange::EthereumTransactionInclusionProof;
use std::time::Duration;
@@ -92,8 +94,8 @@ impl SourceBlock for EthereumSourceBlock {
fn id(&self) -> EthereumHeaderId {
HeaderId(
self.0.number.expect(crate::ethereum_types::HEADER_ID_PROOF).as_u64(),
self.0.hash.expect(crate::ethereum_types::HEADER_ID_PROOF),
self.0.number.expect(HEADER_ID_PROOF).as_u64(),
self.0.hash.expect(HEADER_ID_PROOF),
)
}
@@ -120,7 +122,7 @@ impl SourceTransaction for EthereumSourceTransaction {
/// Ethereum node as transactions proof source.
struct EthereumTransactionsSource {
client: EthereumRpcClient,
client: EthereumClient,
}
#[async_trait]
@@ -136,6 +138,7 @@ impl SourceClient<EthereumToSubstrateExchange> for EthereumTransactionsSource {
.header_by_hash_with_transactions(hash)
.await
.map(EthereumSourceBlock)
.map_err(Into::into)
}
async fn block_by_number(&self, number: u64) -> Result<EthereumSourceBlock, Self::Error> {
@@ -143,6 +146,7 @@ impl SourceClient<EthereumToSubstrateExchange> for EthereumTransactionsSource {
.header_by_number_with_transactions(number)
.await
.map(EthereumSourceBlock)
.map_err(Into::into)
}
async fn transaction_block(
@@ -278,7 +282,7 @@ fn run_single_transaction_relay(params: EthereumExchangeParams, eth_tx_hash: H25
} = params;
let result = local_pool.run_until(async move {
let eth_client = EthereumRpcClient::new(eth_params);
let eth_client = EthereumClient::new(eth_params);
let sub_client = SubstrateRpcClient::new(sub_params, instance).await?;
let source = EthereumTransactionsSource { client: eth_client };
@@ -321,7 +325,7 @@ fn run_auto_transactions_relay_loop(params: EthereumExchangeParams, eth_start_wi
} = params;
let do_run_loop = move || -> Result<(), String> {
let eth_client = EthereumRpcClient::new(eth_params);
let eth_client = EthereumClient::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))?;
@@ -16,14 +16,14 @@
//! Submitting Ethereum -> Substrate exchange transactions.
use crate::ethereum_client::{EthereumConnectionParams, EthereumRpcClient, EthereumSigningParams};
use crate::ethereum_types::{CallRequest, U256};
use crate::rpc::EthereumRpc;
use bp_eth_poa::{
signatures::{SecretKey, SignTransaction},
UnsignedTransaction,
};
use relay_ethereum_client::{
types::{CallRequest, U256},
Client as EthereumClient, ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams,
};
use rialto_runtime::exchange::LOCK_FUNDS_ADDRESS;
/// Ethereum exchange transaction params.
@@ -54,7 +54,7 @@ pub fn run(params: EthereumExchangeSubmitParams) {
} = params;
let result: Result<_, String> = local_pool.run_until(async move {
let eth_client = EthereumRpcClient::new(eth_params);
let eth_client = EthereumClient::new(eth_params);
let eth_signer_address = eth_sign.signer.address();
let sub_recipient_encoded = sub_recipient;
@@ -16,26 +16,27 @@
//! Ethereum PoA -> Substrate synchronization.
use crate::ethereum_client::{EthereumConnectionParams, EthereumHighLevelRpc, EthereumRpcClient};
use crate::ethereum_types::{
EthereumHeaderId, EthereumHeadersSyncPipeline, EthereumSyncHeader as Header, QueuedEthereumHeader, Receipt,
};
use crate::ethereum_client::EthereumHighLevelRpc;
use crate::instances::BridgeInstance;
use crate::rpc::{EthereumRpc, SubstrateRpc};
use crate::rpc::SubstrateRpc;
use crate::rpc_errors::RpcError;
use crate::substrate_client::{
SubmitEthereumHeaders, SubstrateConnectionParams, SubstrateRpcClient, SubstrateSigningParams,
};
use crate::substrate_types::into_substrate_ethereum_header;
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
use async_trait::async_trait;
use codec::Encode;
use headers_relay::{
sync::{HeadersSyncParams, TargetTransactionMode},
sync_loop::{SourceClient, TargetClient},
sync_types::{SourceHeader, SubmittedHeaders},
sync_types::{HeadersSyncPipeline, QueuedHeader, SourceHeader, SubmittedHeaders},
};
use relay_ethereum_client::{
types::{HeaderHash, HeaderId as EthereumHeaderId, Receipt, SyncHeader as Header},
Client as EthereumClient, ConnectionParams as EthereumConnectionParams,
};
use relay_utils::metrics::MetricsParams;
use web3::types::H256;
use std::fmt::Debug;
use std::{collections::HashSet, time::Duration};
@@ -78,14 +79,40 @@ pub struct EthereumSyncParams {
pub instance: Box<dyn BridgeInstance>,
}
/// Ethereum synchronization pipeline.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct EthereumHeadersSyncPipeline;
impl HeadersSyncPipeline for EthereumHeadersSyncPipeline {
const SOURCE_NAME: &'static str = "Ethereum";
const TARGET_NAME: &'static str = "Substrate";
type Hash = HeaderHash;
type Number = u64;
type Header = Header;
type Extra = Vec<Receipt>;
type Completion = ();
fn estimate_size(source: &QueuedHeader<Self>) -> usize {
into_substrate_ethereum_header(source.header()).encode().len()
+ into_substrate_ethereum_receipts(source.extra())
.map(|extra| extra.encode().len())
.unwrap_or(0)
}
}
/// Queued ethereum header ID.
pub type QueuedEthereumHeader = QueuedHeader<EthereumHeadersSyncPipeline>;
/// Ethereum client as headers source.
struct EthereumHeadersSource {
/// Ethereum node client.
client: EthereumRpcClient,
client: EthereumClient,
}
impl EthereumHeadersSource {
fn new(client: EthereumRpcClient) -> Self {
fn new(client: EthereumClient) -> Self {
Self { client }
}
}
@@ -95,15 +122,23 @@ impl SourceClient<EthereumHeadersSyncPipeline> for EthereumHeadersSource {
type Error = RpcError;
async fn best_block_number(&self) -> Result<u64, Self::Error> {
self.client.best_block_number().await
self.client.best_block_number().await.map_err(Into::into)
}
async fn header_by_hash(&self, hash: H256) -> Result<Header, Self::Error> {
self.client.header_by_hash(hash).await.map(Into::into)
async fn header_by_hash(&self, hash: HeaderHash) -> Result<Header, Self::Error> {
self.client
.header_by_hash(hash)
.await
.map(Into::into)
.map_err(Into::into)
}
async fn header_by_number(&self, number: u64) -> Result<Header, Self::Error> {
self.client.header_by_number(number).await.map(Into::into)
self.client
.header_by_number(number)
.await
.map(Into::into)
.map_err(Into::into)
}
async fn header_completion(&self, id: EthereumHeaderId) -> Result<(EthereumHeaderId, Option<()>), Self::Error> {
@@ -192,7 +227,7 @@ pub fn run(params: EthereumSyncParams) -> Result<(), RpcError> {
instance,
} = params;
let eth_client = EthereumRpcClient::new(eth_params);
let eth_client = EthereumClient::new(eth_params);
let sub_client = async_std::task::block_on(async { SubstrateRpcClient::new(sub_params, instance).await })?;
let sign_sub_transactions = match sync_params.target_tx_mode {
+1 -1
View File
@@ -23,7 +23,7 @@
//!
//! This module helps by preparing the correct `Call`s for each of the different pallet instances.
use crate::ethereum_types::QueuedEthereumHeader;
use crate::ethereum_sync_loop::QueuedEthereumHeader;
use crate::substrate_types::{into_substrate_ethereum_header, into_substrate_ethereum_receipts};
use rialto_runtime::exchange::EthereumTransactionInclusionProof as Proof;
+13 -10
View File
@@ -21,7 +21,6 @@ mod ethereum_deploy_contract;
mod ethereum_exchange;
mod ethereum_exchange_submit;
mod ethereum_sync_loop;
mod ethereum_types;
mod instances;
mod rpc;
mod rpc_errors;
@@ -29,7 +28,6 @@ mod substrate_client;
mod substrate_sync_loop;
mod substrate_types;
use ethereum_client::{EthereumConnectionParams, EthereumSigningParams};
use ethereum_deploy_contract::EthereumDeployContractParams;
use ethereum_exchange::EthereumExchangeParams;
use ethereum_exchange_submit::EthereumExchangeSubmitParams;
@@ -44,6 +42,7 @@ use substrate_client::{SubstrateConnectionParams, SubstrateSigningParams};
use substrate_sync_loop::SubstrateSyncParams;
use headers_relay::sync::HeadersSyncParams;
use relay_ethereum_client::{ConnectionParams as EthereumConnectionParams, SigningParams as EthereumSigningParams};
use std::io::Write;
fn main() {
@@ -250,13 +249,14 @@ fn ethereum_sync_params(matches: &clap::ArgMatches) -> Result<EthereumSyncParams
fn substrate_sync_params(matches: &clap::ArgMatches) -> Result<SubstrateSyncParams, String> {
use crate::substrate_sync_loop::consts::*;
let eth_contract_address: ethereum_types::Address = if let Some(eth_contract) = matches.value_of("eth-contract") {
eth_contract.parse().map_err(|e| format!("{}", e))?
} else {
"731a10897d267e19b34503ad902d0a29173ba4b1"
.parse()
.expect("address is hardcoded, thus valid; qed")
};
let eth_contract_address: relay_ethereum_client::types::Address =
if let Some(eth_contract) = matches.value_of("eth-contract") {
eth_contract.parse().map_err(|e| format!("{}", e))?
} else {
"731a10897d267e19b34503ad902d0a29173ba4b1"
.parse()
.expect("address is hardcoded, thus valid; qed")
};
let params = SubstrateSyncParams {
sub_params: substrate_connection_params(matches)?,
@@ -313,7 +313,10 @@ fn ethereum_deploy_contract_params(matches: &clap::ArgMatches) -> Result<Ethereu
fn ethereum_exchange_submit_params(matches: &clap::ArgMatches) -> Result<EthereumExchangeSubmitParams, String> {
let eth_nonce = if let Some(eth_nonce) = matches.value_of("eth-nonce") {
Some(ethereum_types::U256::from_dec_str(&eth_nonce).map_err(|e| format!("Failed to parse eth-nonce: {}", e))?)
Some(
relay_ethereum_client::types::U256::from_dec_str(&eth_nonce)
.map_err(|e| format!("Failed to parse eth-nonce: {}", e))?,
)
} else {
None
};
+1 -59
View File
@@ -23,11 +23,6 @@
#![allow(unused_variables)]
use std::result;
use crate::ethereum_types::{
Address as EthAddress, Bytes, CallRequest, EthereumHeaderId, Header as EthereumHeader,
HeaderWithTransactions as EthereumHeaderWithTransactions, Receipt, SignedRawTx, Transaction as EthereumTransaction,
TransactionHash as EthereumTxHash, H256, U256, U64,
};
use crate::rpc_errors::RpcError;
use crate::substrate_types::{
Hash as SubstrateHash, Header as SubstrateHeader, Number as SubBlockNumber, SignedBlock as SubstrateBlock,
@@ -35,36 +30,12 @@ use crate::substrate_types::{
use async_trait::async_trait;
use bp_eth_poa::AuraHeader as SubstrateEthereumHeader;
use relay_ethereum_client::types::{Bytes, HeaderId as EthereumHeaderId};
type Result<T> = result::Result<T, RpcError>;
type GrandpaAuthorityList = Vec<u8>;
jsonrpsee::rpc_api! {
pub(crate) Ethereum {
#[rpc(method = "eth_estimateGas", positional_params)]
fn estimate_gas(call_request: CallRequest) -> U256;
#[rpc(method = "eth_blockNumber", positional_params)]
fn block_number() -> U64;
#[rpc(method = "eth_getBlockByNumber", positional_params)]
fn get_block_by_number(block_number: U64, full_tx_objs: bool) -> EthereumHeader;
#[rpc(method = "eth_getBlockByHash", positional_params)]
fn get_block_by_hash(hash: H256, full_tx_objs: bool) -> EthereumHeader;
#[rpc(method = "eth_getBlockByNumber", positional_params)]
fn get_block_by_number_with_transactions(number: U64, full_tx_objs: bool) -> EthereumHeaderWithTransactions;
#[rpc(method = "eth_getBlockByHash", positional_params)]
fn get_block_by_hash_with_transactions(hash: H256, full_tx_objs: bool) -> EthereumHeaderWithTransactions;
#[rpc(method = "eth_getTransactionByHash", positional_params)]
fn transaction_by_hash(hash: H256) -> Option<EthereumTransaction>;
#[rpc(method = "eth_getTransactionReceipt", positional_params)]
fn get_transaction_receipt(transaction_hash: H256) -> Receipt;
#[rpc(method = "eth_getTransactionCount", positional_params)]
fn get_transaction_count(address: EthAddress) -> U256;
#[rpc(method = "eth_submitTransaction", positional_params)]
fn submit_transaction(transaction: Bytes) -> EthereumTxHash;
#[rpc(method = "eth_call", positional_params)]
fn call(transaction_call: CallRequest) -> Bytes;
}
pub(crate) Substrate {
#[rpc(method = "chain_getHeader", positional_params)]
fn chain_get_header(block_hash: Option<SubstrateHash>) -> SubstrateHeader;
@@ -81,35 +52,6 @@ jsonrpsee::rpc_api! {
}
}
/// The API for the supported Ethereum RPC methods.
#[async_trait]
pub trait EthereumRpc {
/// Estimate gas usage for the given call.
async fn estimate_gas(&self, call_request: CallRequest) -> Result<U256>;
/// Retrieve number of the best known block from the Ethereum node.
async fn best_block_number(&self) -> Result<u64>;
/// Retrieve block header by its number from Ethereum node.
async fn header_by_number(&self, block_number: u64) -> Result<EthereumHeader>;
/// Retrieve block header by its hash from Ethereum node.
async fn header_by_hash(&self, hash: H256) -> Result<EthereumHeader>;
/// Retrieve block header and its transactions by its number from Ethereum node.
async fn header_by_number_with_transactions(&self, block_number: u64) -> Result<EthereumHeaderWithTransactions>;
/// Retrieve block header and its transactions by its hash from Ethereum node.
async fn header_by_hash_with_transactions(&self, hash: H256) -> Result<EthereumHeaderWithTransactions>;
/// Retrieve transaction by its hash from Ethereum node.
async fn transaction_by_hash(&self, hash: H256) -> Result<Option<EthereumTransaction>>;
/// Retrieve transaction receipt by transaction hash.
async fn transaction_receipt(&self, transaction_hash: H256) -> Result<Receipt>;
/// Get the nonce of the given account.
async fn account_nonce(&self, address: EthAddress) -> Result<U256>;
/// Submit an Ethereum transaction.
///
/// The transaction must already be signed before sending it through this method.
async fn submit_transaction(&self, signed_raw_tx: SignedRawTx) -> Result<EthereumTxHash>;
/// Submit a call to an Ethereum smart contract.
async fn eth_call(&self, call_transaction: CallRequest) -> Result<Bytes>;
}
/// The API for the supported Substrate RPC methods.
#[async_trait]
pub trait SubstrateRpc {
+6 -33
View File
@@ -15,6 +15,7 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use jsonrpsee::client::RequestError;
use relay_ethereum_client::Error as EthereumNodeError;
use relay_utils::MaybeConnectionError;
/// Contains common errors that can occur when
@@ -76,7 +77,11 @@ impl From<ethabi::Error> for RpcError {
impl MaybeConnectionError for RpcError {
fn is_connection_error(&self) -> bool {
matches!(*self, RpcError::Request(RequestError::TransportError(_)))
match self {
RpcError::Request(RequestError::TransportError(_)) => true,
RpcError::Ethereum(ref error) => error.is_connection_error(),
_ => false,
}
}
}
@@ -86,38 +91,6 @@ impl From<codec::Error> for RpcError {
}
}
/// Errors that can occur only when interacting with
/// an Ethereum node through RPC.
#[derive(Debug)]
pub enum EthereumNodeError {
/// Failed to parse response.
ResponseParseFailed(String),
/// We have received a header with missing fields.
IncompleteHeader,
/// We have received a transaction missing a `raw` field.
IncompleteTransaction,
/// An invalid Substrate block number was received from
/// an Ethereum node.
InvalidSubstrateBlockNumber,
/// An invalid index has been received from an Ethereum node.
InvalidIncompleteIndex,
}
impl ToString for EthereumNodeError {
fn to_string(&self) -> String {
match self {
Self::ResponseParseFailed(e) => e.to_string(),
Self::IncompleteHeader => {
"Incomplete Ethereum Header Received (missing some of required fields - hash, number, logs_bloom)"
.to_string()
}
Self::IncompleteTransaction => "Incomplete Ethereum Transaction (missing required field - raw)".to_string(),
Self::InvalidSubstrateBlockNumber => "Received an invalid Substrate block from Ethereum Node".to_string(),
Self::InvalidIncompleteIndex => "Received an invalid incomplete index from Ethereum Node".to_string(),
}
}
}
/// Errors that can occur only when interacting with
/// a Substrate node through RPC.
#[derive(Debug)]
@@ -14,7 +14,7 @@
// 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 crate::ethereum_types::{Bytes, EthereumHeaderId, QueuedEthereumHeader, H256};
use crate::ethereum_sync_loop::QueuedEthereumHeader;
use crate::instances::BridgeInstance;
use crate::rpc::{Substrate, SubstrateRpc};
use crate::rpc_errors::RpcError;
@@ -28,6 +28,7 @@ use jsonrpsee::raw::RawClient;
use jsonrpsee::transport::http::HttpTransportClient;
use jsonrpsee::Client;
use num_traits::Zero;
use relay_ethereum_client::types::{Bytes, HeaderId as EthereumHeaderId, H256};
use relay_utils::HeaderId;
use sp_core::crypto::Pair;
use sp_runtime::traits::IdentifyAccount;
@@ -16,10 +16,7 @@
//! Substrate -> Ethereum synchronization.
use crate::ethereum_client::{
EthereumConnectionParams, EthereumHighLevelRpc, EthereumRpcClient, EthereumSigningParams,
};
use crate::ethereum_types::Address;
use crate::ethereum_client::EthereumHighLevelRpc;
use crate::instances::BridgeInstance;
use crate::rpc::SubstrateRpc;
use crate::rpc_errors::RpcError;
@@ -35,6 +32,10 @@ use headers_relay::{
sync_loop::{SourceClient, TargetClient},
sync_types::{SourceHeader, SubmittedHeaders},
};
use relay_ethereum_client::{
types::Address, Client as EthereumClient, ConnectionParams as EthereumConnectionParams,
SigningParams as EthereumSigningParams,
};
use relay_utils::metrics::MetricsParams;
use std::fmt::Debug;
@@ -125,7 +126,7 @@ impl SourceClient<SubstrateHeadersSyncPipeline> for SubstrateHeadersSource {
/// Ethereum client as Substrate headers target.
struct EthereumHeadersTarget {
/// Ethereum node client.
client: EthereumRpcClient,
client: EthereumClient,
/// Bridge contract address.
contract: Address,
/// Ethereum signing params.
@@ -133,7 +134,7 @@ struct EthereumHeadersTarget {
}
impl EthereumHeadersTarget {
fn new(client: EthereumRpcClient, contract: Address, sign_params: EthereumSigningParams) -> Self {
fn new(client: EthereumClient, contract: Address, sign_params: EthereumSigningParams) -> Self {
Self {
client,
contract,
@@ -194,7 +195,7 @@ pub fn run(params: SubstrateSyncParams) -> Result<(), RpcError> {
instance,
} = params;
let eth_client = EthereumRpcClient::new(eth_params);
let eth_client = EthereumClient::new(eth_params);
let sub_client = async_std::task::block_on(async { SubstrateRpcClient::new(sub_params, instance).await })?;
let target = EthereumHeadersTarget::new(eth_client, eth_contract_address, eth_sign);
@@ -14,10 +14,6 @@
// 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 crate::ethereum_types::{
Header as EthereumHeader, Receipt as EthereumReceipt, HEADER_ID_PROOF as ETHEREUM_HEADER_ID_PROOF,
};
use codec::Encode;
use headers_relay::sync_types::{HeadersSyncPipeline, QueuedHeader, SourceHeader};
use relay_utils::HeaderId;
@@ -26,6 +22,9 @@ pub use bp_eth_poa::{
Address, AuraHeader as SubstrateEthereumHeader, Bloom, Bytes, LogEntry as SubstrateEthereumLogEntry,
Receipt as SubstrateEthereumReceipt, TransactionOutcome as SubstrateEthereumTransactionOutcome, H256, U256,
};
use relay_ethereum_client::types::{
Header as EthereumHeader, Receipt as EthereumReceipt, HEADER_ID_PROOF as ETHEREUM_HEADER_ID_PROOF,
};
/// Substrate header hash.
pub type Hash = rialto_runtime::Hash;