mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 23:21:02 +00:00
Prepare for sub to eth relay (#248)
* fixed PoA contract deploy (granda_authorities call) * pause if all submitted headers were rejected * give funds to Bertha and Carlos * max 1 active PoA transaction in headers sync :( * display initial header id when deploying PoA contract * cargo fmt + clipy * fix compilation * Update relays/ethereum/src/sync_types.rs Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update relays/ethereum/src/utils.rs Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
fddfbb5b1c
commit
b98b7d2e43
@@ -21,7 +21,8 @@ use crate::ethereum_types::{
|
||||
use crate::rpc::{Ethereum, EthereumRpc};
|
||||
use crate::rpc_errors::{EthereumNodeError, RpcError};
|
||||
use crate::substrate_types::{GrandpaJustification, Hash as SubstrateHash, QueuedSubstrateHeader, SubstrateHeaderId};
|
||||
use crate::sync_types::{HeaderId, MaybeConnectionError, SubmittedHeaders};
|
||||
use crate::sync_types::{HeaderId, SubmittedHeaders};
|
||||
use crate::utils::MaybeConnectionError;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
@@ -19,7 +19,8 @@ use crate::ethereum_client::{
|
||||
};
|
||||
use crate::rpc::SubstrateRpc;
|
||||
use crate::substrate_client::{SubstrateConnectionParams, SubstrateRpcClient};
|
||||
use crate::substrate_types::{Hash as SubstrateHash, Header as SubstrateHeader};
|
||||
use crate::substrate_types::{Hash as SubstrateHash, Header as SubstrateHeader, SubstrateHeaderId};
|
||||
use crate::sync_types::HeaderId;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use num_traits::Zero;
|
||||
@@ -66,18 +67,19 @@ pub fn run(params: EthereumDeployContractParams) {
|
||||
let eth_client = EthereumRpcClient::new(params.eth);
|
||||
let sub_client = SubstrateRpcClient::new(params.sub).await?;
|
||||
|
||||
let (initial_header_hash, initial_header) = prepare_initial_header(&sub_client, params.sub_initial_header).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_set = prepare_initial_authorities_set(
|
||||
&sub_client,
|
||||
initial_header_hash,
|
||||
initial_header_id.1,
|
||||
params.sub_initial_authorities_set,
|
||||
).await?;
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Deploying Ethereum contract.\r\n\tInitial header: {:?}\r\n\tInitial header encoded: {}\r\n\tInitial authorities set ID: {}\r\n\tInitial authorities set: {}",
|
||||
"Deploying Ethereum contract.\r\n\tInitial header: {:?}\r\n\tInitial header id: {:?}\r\n\tInitial header encoded: {}\r\n\tInitial authorities set ID: {}\r\n\tInitial authorities set: {}",
|
||||
initial_header,
|
||||
initial_header_id,
|
||||
hex::encode(&initial_header),
|
||||
initial_set_id,
|
||||
hex::encode(&initial_set),
|
||||
@@ -102,16 +104,19 @@ pub fn run(params: EthereumDeployContractParams) {
|
||||
async fn prepare_initial_header(
|
||||
sub_client: &SubstrateRpcClient,
|
||||
sub_initial_header: Option<Vec<u8>>,
|
||||
) -> Result<(SubstrateHash, Vec<u8>), String> {
|
||||
) -> Result<(SubstrateHeaderId, Vec<u8>), String> {
|
||||
match sub_initial_header {
|
||||
Some(raw_initial_header) => match SubstrateHeader::decode(&mut &raw_initial_header[..]) {
|
||||
Ok(initial_header) => Ok((initial_header.hash(), raw_initial_header)),
|
||||
Ok(initial_header) => Ok((
|
||||
HeaderId(initial_header.number, initial_header.hash()),
|
||||
raw_initial_header,
|
||||
)),
|
||||
Err(error) => Err(format!("Error decoding initial header: {}", error)),
|
||||
},
|
||||
None => {
|
||||
let initial_header = sub_client.header_by_number(Zero::zero()).await;
|
||||
initial_header
|
||||
.map(|header| (header.hash(), header.encode()))
|
||||
.map(|header| (HeaderId(Zero::zero(), header.hash()), header.encode()))
|
||||
.map_err(|error| format!("Error reading Substrate genesis header: {:?}", error))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
//! Relaying proofs of exchange transaction.
|
||||
|
||||
use crate::sync_types::MaybeConnectionError;
|
||||
use crate::utils::{MaybeConnectionError, StringifiedMaybeConnectionError};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use std::{
|
||||
@@ -135,14 +135,6 @@ pub struct RelayedBlockTransactions {
|
||||
pub failed: usize,
|
||||
}
|
||||
|
||||
/// Stringified error that may be either connection-related or not.
|
||||
enum StringifiedMaybeConnectionError {
|
||||
/// The error is connection-related error.
|
||||
Connection(String),
|
||||
/// The error is connection-unrelated error.
|
||||
NonConnection(String),
|
||||
}
|
||||
|
||||
/// Relay all suitable transactions from single block.
|
||||
///
|
||||
/// If connection error occurs, returns Err with number of successfully processed transactions.
|
||||
@@ -448,34 +440,6 @@ async fn wait_header_finalized<P: TransactionProofPipeline>(
|
||||
}
|
||||
}
|
||||
|
||||
impl StringifiedMaybeConnectionError {
|
||||
fn new(is_connection_error: bool, error: String) -> Self {
|
||||
if is_connection_error {
|
||||
StringifiedMaybeConnectionError::Connection(error)
|
||||
} else {
|
||||
StringifiedMaybeConnectionError::NonConnection(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybeConnectionError for StringifiedMaybeConnectionError {
|
||||
fn is_connection_error(&self) -> bool {
|
||||
match *self {
|
||||
StringifiedMaybeConnectionError::Connection(_) => true,
|
||||
StringifiedMaybeConnectionError::NonConnection(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for StringifiedMaybeConnectionError {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
StringifiedMaybeConnectionError::Connection(ref err) => err.clone(),
|
||||
StringifiedMaybeConnectionError::NonConnection(ref err) => err.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -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::sync_types::MaybeConnectionError;
|
||||
use crate::utils::MaybeConnectionError;
|
||||
|
||||
use jsonrpsee::client::RequestError;
|
||||
|
||||
|
||||
@@ -187,9 +187,9 @@ impl SubstrateRpc for SubstrateRpcClient {
|
||||
|
||||
async fn grandpa_authorities_set(&self, block: Hash) -> Result<GrandpaAuthorityList> {
|
||||
let call = SUB_API_GRANDPA_AUTHORITIES.to_string();
|
||||
let data = Bytes(block.as_bytes().to_vec());
|
||||
let data = Bytes(Vec::new());
|
||||
|
||||
let encoded_response = Substrate::state_call(&self.client, call, data, None).await?;
|
||||
let encoded_response = Substrate::state_call(&self.client, call, data, Some(block)).await?;
|
||||
let authority_list = encoded_response.0;
|
||||
|
||||
Ok(authority_list)
|
||||
|
||||
@@ -42,7 +42,7 @@ 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 = 4;
|
||||
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;
|
||||
|
||||
|
||||
@@ -17,10 +17,8 @@
|
||||
use crate::metrics::{start as metrics_start, GlobalMetrics, MetricsParams};
|
||||
use crate::sync::HeadersSyncParams;
|
||||
use crate::sync_loop_metrics::SyncLoopMetrics;
|
||||
use crate::sync_types::{
|
||||
HeaderIdOf, HeaderStatus, HeadersSyncPipeline, MaybeConnectionError, QueuedHeader, SubmittedHeaders,
|
||||
};
|
||||
use crate::utils::retry_backoff;
|
||||
use crate::sync_types::{HeaderIdOf, HeaderStatus, HeadersSyncPipeline, QueuedHeader, SubmittedHeaders};
|
||||
use crate::utils::{format_ids, retry_backoff, MaybeConnectionError, StringifiedMaybeConnectionError};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use backoff::{backoff::Backoff, ExponentialBackoff};
|
||||
@@ -309,7 +307,16 @@ pub fn run<P: HeadersSyncPipeline, TC: TargetClient<P>>(
|
||||
submitted_headers = target_submit_header_future => {
|
||||
// following line helps Rust understand the type of `submitted_headers` :/
|
||||
let submitted_headers: SubmittedHeaders<HeaderIdOf<P>, TC::Error> = submitted_headers;
|
||||
let maybe_fatal_error = submitted_headers.fatal_error.map(Err).unwrap_or(Ok(()));
|
||||
let submitted_headers_str = format!("{}", submitted_headers);
|
||||
let maybe_fatal_error = match submitted_headers.fatal_error {
|
||||
Some(fatal_error) => Err(StringifiedMaybeConnectionError::new(
|
||||
fatal_error.is_connection_error(),
|
||||
format!("{:?}", fatal_error),
|
||||
)),
|
||||
None if submitted_headers.submitted.is_empty() && submitted_headers.incomplete.is_empty() =>
|
||||
Err(StringifiedMaybeConnectionError::new(false, "All headers were rejected".into())),
|
||||
None => Ok(()),
|
||||
};
|
||||
|
||||
target_client_is_online = process_future_result(
|
||||
maybe_fatal_error,
|
||||
@@ -320,6 +327,8 @@ pub fn run<P: HeadersSyncPipeline, TC: TargetClient<P>>(
|
||||
|| format!("Error submitting headers to {} node", P::TARGET_NAME),
|
||||
);
|
||||
|
||||
log::debug!(target: "bridge", "Header submit result: {}", submitted_headers_str);
|
||||
|
||||
sync.headers_mut().headers_submitted(submitted_headers.submitted);
|
||||
sync.headers_mut().add_incomplete_headers(submitted_headers.incomplete);
|
||||
},
|
||||
@@ -434,17 +443,12 @@ pub fn run<P: HeadersSyncPipeline, TC: TargetClient<P>>(
|
||||
} else if let Some(headers) =
|
||||
sync.select_headers_to_submit(last_update_time.elapsed() > BACKUP_STALL_SYNC_TIMEOUT)
|
||||
{
|
||||
let ids = match headers.len() {
|
||||
1 => format!("{:?}", headers[0].id()),
|
||||
2 => format!("[{:?}, {:?}]", headers[0].id(), headers[1].id()),
|
||||
len => format!("[{:?} ... {:?}]", headers[0].id(), headers[len - 1].id()),
|
||||
};
|
||||
log::debug!(
|
||||
target: "bridge",
|
||||
"Submitting {} header(s) to {} node: {:?}",
|
||||
headers.len(),
|
||||
P::TARGET_NAME,
|
||||
ids,
|
||||
format_ids(headers.iter().map(|header| header.id())),
|
||||
);
|
||||
|
||||
let headers = headers.into_iter().cloned().collect();
|
||||
|
||||
@@ -17,10 +17,8 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::sync_loop::{process_future_result, run, SourceClient, TargetClient};
|
||||
use crate::sync_types::{
|
||||
HeaderId, HeadersSyncPipeline, MaybeConnectionError, QueuedHeader, SourceHeader, SubmittedHeaders,
|
||||
};
|
||||
use crate::utils::retry_backoff;
|
||||
use crate::sync_types::{HeaderId, HeadersSyncPipeline, QueuedHeader, SourceHeader, SubmittedHeaders};
|
||||
use crate::utils::{retry_backoff, MaybeConnectionError};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use backoff::backoff::Backoff;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// 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::utils::format_ids;
|
||||
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
/// Ethereum header Id.
|
||||
@@ -43,12 +45,6 @@ pub enum HeaderStatus {
|
||||
Synced,
|
||||
}
|
||||
|
||||
/// Error type that can signal connection errors.
|
||||
pub trait MaybeConnectionError {
|
||||
/// Returns true if error (maybe) represents connection error.
|
||||
fn is_connection_error(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Headers synchronization pipeline.
|
||||
pub trait HeadersSyncPipeline: Clone + Copy {
|
||||
/// Name of the headers source.
|
||||
@@ -192,3 +188,17 @@ impl<Id, Error> Default for SubmittedHeaders<Id, Error> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Id: std::fmt::Debug, Error> std::fmt::Display for SubmittedHeaders<Id, Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let submitted = format_ids(self.submitted.iter());
|
||||
let incomplete = format_ids(self.incomplete.iter());
|
||||
let rejected = format_ids(self.rejected.iter());
|
||||
|
||||
write!(
|
||||
f,
|
||||
"Submitted: {}, Incomplete: {}, Rejected: {}",
|
||||
submitted, incomplete, rejected
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,50 @@ macro_rules! bail_on_arg_error {
|
||||
};
|
||||
}
|
||||
|
||||
/// Error type that can signal connection errors.
|
||||
pub trait MaybeConnectionError {
|
||||
/// Returns true if error (maybe) represents connection error.
|
||||
fn is_connection_error(&self) -> bool;
|
||||
}
|
||||
|
||||
/// Stringified error that may be either connection-related or not.
|
||||
#[derive(Debug)]
|
||||
pub enum StringifiedMaybeConnectionError {
|
||||
/// The error is connection-related error.
|
||||
Connection(String),
|
||||
/// The error is connection-unrelated error.
|
||||
NonConnection(String),
|
||||
}
|
||||
|
||||
impl StringifiedMaybeConnectionError {
|
||||
/// Create new stringified connection error.
|
||||
pub fn new(is_connection_error: bool, error: String) -> Self {
|
||||
if is_connection_error {
|
||||
StringifiedMaybeConnectionError::Connection(error)
|
||||
} else {
|
||||
StringifiedMaybeConnectionError::NonConnection(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybeConnectionError for StringifiedMaybeConnectionError {
|
||||
fn is_connection_error(&self) -> bool {
|
||||
match *self {
|
||||
StringifiedMaybeConnectionError::Connection(_) => true,
|
||||
StringifiedMaybeConnectionError::NonConnection(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for StringifiedMaybeConnectionError {
|
||||
fn to_string(&self) -> String {
|
||||
match *self {
|
||||
StringifiedMaybeConnectionError::Connection(ref err) => err.clone(),
|
||||
StringifiedMaybeConnectionError::NonConnection(ref err) => err.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Exponential backoff for connection-unrelated errors retries.
|
||||
pub fn retry_backoff() -> ExponentialBackoff {
|
||||
let mut backoff = ExponentialBackoff::default();
|
||||
@@ -51,3 +95,22 @@ pub fn retry_backoff() -> ExponentialBackoff {
|
||||
backoff.max_interval = MAX_BACKOFF_INTERVAL;
|
||||
backoff
|
||||
}
|
||||
|
||||
/// Compact format of IDs vector.
|
||||
pub fn format_ids<Id: std::fmt::Debug>(mut ids: impl ExactSizeIterator<Item = Id>) -> String {
|
||||
const NTH_PROOF: &str = "we have checked len; qed";
|
||||
match ids.len() {
|
||||
0 => "<nothing>".into(),
|
||||
1 => format!("{:?}", ids.next().expect(NTH_PROOF)),
|
||||
2 => {
|
||||
let id0 = ids.next().expect(NTH_PROOF);
|
||||
let id1 = ids.next().expect(NTH_PROOF);
|
||||
format!("[{:?}, {:?}]", id0, id1)
|
||||
}
|
||||
len => {
|
||||
let id0 = ids.next().expect(NTH_PROOF);
|
||||
let id_last = ids.last().expect(NTH_PROOF);
|
||||
format!("{}:[{:?} ... {:?}]", len, id0, id_last)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user