mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 17:31:03 +00:00
Unify error enums in substrate and ethereum clients with thiserror (#1094)
* Unify error enums in substrate and ethereum clients with `thiserror` Related to https://github.com/paritytech/parity-bridges-common/issues/857 * Add license pre-amble * rustfmt * Fix spelling
This commit is contained in:
committed by
Bastian Köcher
parent
7b4f1c2236
commit
5842968273
@@ -7,6 +7,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
thiserror = "1.0.26"
|
||||
async-std = "1.9.0"
|
||||
async-trait = "0.1.42"
|
||||
codec = { package = "parity-scale-codec", version = "2.2.0" }
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2019-2021 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/>.
|
||||
|
||||
//! Relay errors.
|
||||
|
||||
use relay_substrate_client as client;
|
||||
use sp_finality_grandpa::AuthorityList;
|
||||
use sp_runtime::traits::MaybeDisplay;
|
||||
use std::fmt::Debug;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Relay errors.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error<Hash: Debug + MaybeDisplay, HeaderNumber: Debug + MaybeDisplay> {
|
||||
/// Failed to submit signed extrinsic from to the target chain.
|
||||
#[error("Failed to submit {0} transaction: {1:?}")]
|
||||
SubmitTransaction(&'static str, client::Error),
|
||||
/// Failed subscribe to justification stream of the source chain.
|
||||
#[error("Failed to subscribe to {0} justifications: {1:?}")]
|
||||
Subscribe(&'static str, client::Error),
|
||||
/// Failed subscribe to read justification from the source chain (client error).
|
||||
#[error("Failed to read {0} justification from the stream: {1}")]
|
||||
ReadJustification(&'static str, client::Error),
|
||||
/// Failed subscribe to read justification from the source chain (stream ended).
|
||||
#[error("Failed to read {0} justification from the stream: stream has ended unexpectedly")]
|
||||
ReadJustificationStreamEnded(&'static str),
|
||||
/// Failed subscribe to decode justification from the source chain.
|
||||
#[error("Failed to decode {0} justification: {1:?}")]
|
||||
DecodeJustification(&'static str, codec::Error),
|
||||
/// GRANDPA authorities read from the source chain are invalid.
|
||||
#[error("Read invalid {0} authorities set: {1:?}")]
|
||||
ReadInvalidAuthorities(&'static str, AuthorityList),
|
||||
/// Failed to guess initial GRANDPA authorities at the given header of the source chain.
|
||||
#[error("Failed to guess initial {0} GRANDPA authorities set id: checked all possible ids in range [0; {1}]")]
|
||||
GuessInitialAuthorities(&'static str, HeaderNumber),
|
||||
/// Failed to retrieve GRANDPA authorities at the given header from the source chain.
|
||||
#[error("Failed to retrive {0} GRANDPA authorities set at header {1}: {2:?}")]
|
||||
RetrieveAuthorities(&'static str, Hash, client::Error),
|
||||
/// Failed to decode GRANDPA authorities at the given header of the source chain.
|
||||
#[error("Failed to decode {0} GRANDPA authorities set at header {1}: {2:?}")]
|
||||
DecodeAuthorities(&'static str, Hash, codec::Error),
|
||||
/// Failed to retrieve header by the hash from the source chain.
|
||||
#[error("Failed to retrieve {0} header with hash {1}: {:?}")]
|
||||
RetrieveHeader(&'static str, Hash, client::Error),
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
//! and authorities set from source to target chain. The headers sync starts
|
||||
//! with this header.
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
use bp_header_chain::{
|
||||
find_grandpa_authorities_scheduled_change,
|
||||
justification::{verify_justification, GrandpaJustification},
|
||||
@@ -32,7 +34,7 @@ use num_traits::{One, Zero};
|
||||
use relay_substrate_client::{Chain, Client};
|
||||
use sp_core::Bytes;
|
||||
use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
use sp_runtime::traits::{Header as HeaderT, Header};
|
||||
|
||||
/// Submit headers-bridge initialization transaction.
|
||||
pub async fn initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
@@ -77,7 +79,7 @@ async fn do_initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
prepare_initialize_transaction: impl FnOnce(TargetChain::Index, InitializationData<SourceChain::Header>) -> Bytes
|
||||
+ Send
|
||||
+ 'static,
|
||||
) -> Result<TargetChain::Hash, String> {
|
||||
) -> Result<TargetChain::Hash, Error<SourceChain::Hash, <SourceChain::Header as Header>::Number>> {
|
||||
let initialization_data = prepare_initialization_data(source_client).await?;
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
@@ -92,41 +94,40 @@ async fn do_initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
prepare_initialize_transaction(transaction_nonce, initialization_data)
|
||||
})
|
||||
.await
|
||||
.map_err(|err| format!("Failed to submit {} transaction: {:?}", TargetChain::NAME, err))?;
|
||||
.map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))?;
|
||||
Ok(initialization_tx_hash)
|
||||
}
|
||||
|
||||
/// Prepare initialization data for the GRANDPA verifier pallet.
|
||||
async fn prepare_initialization_data<SourceChain: Chain>(
|
||||
source_client: Client<SourceChain>,
|
||||
) -> Result<InitializationData<SourceChain::Header>, String> {
|
||||
) -> Result<
|
||||
InitializationData<SourceChain::Header>,
|
||||
Error<SourceChain::Hash, <SourceChain::Header as Header>::Number>,
|
||||
> {
|
||||
// In ideal world we just need to get best finalized header and then to read GRANDPA authorities
|
||||
// set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at this header.
|
||||
//
|
||||
// But now there are problems with this approach - `CurrentSetId` may return invalid value. So
|
||||
// here we're waiting for the next justification, read the authorities set and then try to
|
||||
// figure out the set id with bruteforce.
|
||||
let justifications = source_client.subscribe_justifications().await.map_err(|err| {
|
||||
format!("Failed to subscribe to {} justifications: {:?}", SourceChain::NAME, err)
|
||||
})?;
|
||||
|
||||
let justifications = source_client
|
||||
.subscribe_justifications()
|
||||
.await
|
||||
.map_err(|err| Error::Subscribe(SourceChain::NAME, err))?;
|
||||
// Read next justification - the header that it finalizes will be used as initial header.
|
||||
let justification = justifications
|
||||
.next()
|
||||
.await
|
||||
.map_err(|err| err.to_string())
|
||||
.map_err(|e| Error::ReadJustification(SourceChain::NAME, e))
|
||||
.and_then(|justification| {
|
||||
justification.ok_or_else(|| "stream has ended unexpectedly".into())
|
||||
})
|
||||
.map_err(|err| {
|
||||
format!("Failed to read {} justification from the stream: {}", SourceChain::NAME, err,)
|
||||
justification.ok_or_else(|| Error::ReadJustificationStreamEnded(SourceChain::NAME))
|
||||
})?;
|
||||
|
||||
// Read initial header.
|
||||
let justification: GrandpaJustification<SourceChain::Header> =
|
||||
Decode::decode(&mut &justification.0[..]).map_err(|err| {
|
||||
format!("Failed to decode {} justification: {:?}", SourceChain::NAME, err)
|
||||
})?;
|
||||
Decode::decode(&mut &justification.0[..])
|
||||
.map_err(|err| Error::DecodeJustification(SourceChain::NAME, err))?;
|
||||
|
||||
let (initial_header_hash, initial_header_number) =
|
||||
(justification.commit.target_hash, justification.commit.target_number);
|
||||
@@ -174,11 +175,7 @@ async fn prepare_initialization_data<SourceChain: Chain>(
|
||||
let mut min_possible_block_number = SourceChain::BlockNumber::zero();
|
||||
let authorities_for_verification = VoterSet::new(authorities_for_verification.clone())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"Read invalid {} authorities set: {:?}",
|
||||
SourceChain::NAME,
|
||||
authorities_for_verification,
|
||||
)
|
||||
Error::ReadInvalidAuthorities(SourceChain::NAME, authorities_for_verification)
|
||||
})?;
|
||||
loop {
|
||||
log::trace!(
|
||||
@@ -205,12 +202,7 @@ async fn prepare_initialization_data<SourceChain: Chain>(
|
||||
// there can't be more authorities set changes than headers => if we have reached
|
||||
// `initial_block_number` and still have not found correct value of
|
||||
// `initial_authorities_set_id`, then something else is broken => fail
|
||||
return Err(format!(
|
||||
"Failed to guess initial {} GRANDPA authorities set id: checked all\
|
||||
possible ids in range [0; {}]",
|
||||
SourceChain::NAME,
|
||||
initial_header_number
|
||||
))
|
||||
return Err(Error::GuessInitialAuthorities(SourceChain::NAME, initial_header_number))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,37 +222,24 @@ async fn prepare_initialization_data<SourceChain: Chain>(
|
||||
async fn source_header<SourceChain: Chain>(
|
||||
source_client: &Client<SourceChain>,
|
||||
header_hash: SourceChain::Hash,
|
||||
) -> Result<SourceChain::Header, String> {
|
||||
source_client.header_by_hash(header_hash).await.map_err(|err| {
|
||||
format!(
|
||||
"Failed to retrive {} header with hash {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
header_hash,
|
||||
err,
|
||||
)
|
||||
})
|
||||
) -> Result<SourceChain::Header, Error<SourceChain::Hash, <SourceChain::Header as Header>::Number>>
|
||||
{
|
||||
source_client
|
||||
.header_by_hash(header_hash)
|
||||
.await
|
||||
.map_err(|err| Error::RetrieveHeader(SourceChain::NAME, header_hash, err))
|
||||
}
|
||||
|
||||
/// Read GRANDPA authorities set at given header.
|
||||
async fn source_authorities_set<SourceChain: Chain>(
|
||||
source_client: &Client<SourceChain>,
|
||||
header_hash: SourceChain::Hash,
|
||||
) -> Result<GrandpaAuthoritiesSet, String> {
|
||||
let raw_authorities_set =
|
||||
source_client.grandpa_authorities_set(header_hash).await.map_err(|err| {
|
||||
format!(
|
||||
"Failed to retrive {} GRANDPA authorities set at header {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
header_hash,
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..]).map_err(|err| {
|
||||
format!(
|
||||
"Failed to decode {} GRANDPA authorities set at header {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
header_hash,
|
||||
err,
|
||||
)
|
||||
})
|
||||
) -> Result<GrandpaAuthoritiesSet, Error<SourceChain::Hash, <SourceChain::Header as Header>::Number>>
|
||||
{
|
||||
let raw_authorities_set = source_client
|
||||
.grandpa_authorities_set(header_hash)
|
||||
.await
|
||||
.map_err(|err| Error::RetrieveAuthorities(SourceChain::NAME, header_hash, err))?;
|
||||
GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..])
|
||||
.map_err(|err| Error::DecodeAuthorities(SourceChain::NAME, header_hash, err))
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod conversion_rate_update;
|
||||
pub mod error;
|
||||
pub mod finality_pipeline;
|
||||
pub mod finality_target;
|
||||
pub mod headers_initialize;
|
||||
|
||||
Reference in New Issue
Block a user