diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs
index 4f88e701fb..14035566e6 100644
--- a/bridges/primitives/runtime/src/chain.rs
+++ b/bridges/primitives/runtime/src/chain.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see .
+use crate::HeaderIdProvider;
use codec::{Decode, Encode};
use frame_support::{weights::Weight, Parameter};
use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero};
@@ -143,6 +144,7 @@ pub trait Chain: Send + Sync + 'static {
// https://crates.parity.io/sp_runtime/traits/trait.Header.html
type Header: Parameter
+ HeaderT
+ + HeaderIdProvider
+ MaybeSerializeDeserialize;
/// The user account identifier type for the runtime.
diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs
index ca8a22ee16..982b8f9a0e 100644
--- a/bridges/primitives/runtime/src/lib.rs
+++ b/bridges/primitives/runtime/src/lib.rs
@@ -26,7 +26,7 @@ use frame_system::RawOrigin;
use scale_info::TypeInfo;
use sp_core::{hash::H256, storage::StorageKey};
use sp_io::hashing::blake2_256;
-use sp_runtime::traits::BadOrigin;
+use sp_runtime::traits::{BadOrigin, Header as HeaderT};
use sp_std::{convert::TryFrom, fmt::Debug, vec, vec::Vec};
pub use chain::{
@@ -34,6 +34,7 @@ pub use chain::{
HasherOf, HeaderOf, IndexOf, SignatureOf, TransactionEraOf,
};
pub use frame_support::storage::storage_prefix as storage_value_final_key;
+use num_traits::{CheckedSub, One};
pub use storage_proof::{
Error as StorageProofError, ProofSize as StorageProofSize, StorageProofChecker,
};
@@ -83,6 +84,27 @@ pub const ROOT_ACCOUNT_DERIVATION_PREFIX: &[u8] = b"pallet-bridge/account-deriva
#[derive(RuntimeDebug, Default, Clone, Copy, Eq, Hash, PartialEq)]
pub struct HeaderId(pub Number, pub Hash);
+/// Generic header id provider.
+pub trait HeaderIdProvider {
+ // Get the header id.
+ fn id(&self) -> HeaderId;
+
+ // Get the header id for the parent block.
+ fn parent_id(&self) -> Option>;
+}
+
+impl HeaderIdProvider for Header {
+ fn id(&self) -> HeaderId {
+ HeaderId(*self.number(), self.hash())
+ }
+
+ fn parent_id(&self) -> Option> {
+ self.number()
+ .checked_sub(&One::one())
+ .map(|parent_number| HeaderId(parent_number, *self.parent_hash()))
+ }
+}
+
/// Unique identifier of the chain.
///
/// In addition to its main function (identifying the chain), this type may also be used to
diff --git a/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs b/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs
index a4cec79655..dad1afbf14 100644
--- a/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs
+++ b/bridges/relays/bin-substrate/src/cli/resubmit_transactions.rs
@@ -16,13 +16,14 @@
use crate::cli::{chain_schema::*, Balance};
+use bp_runtime::HeaderIdProvider;
use codec::{Decode, Encode};
use num_traits::{One, Zero};
use relay_substrate_client::{
BlockWithJustification, Chain, Client, Error as SubstrateError, HeaderIdOf, HeaderOf,
SignParam, TransactionSignScheme,
};
-use relay_utils::{FailedClient, HeaderId};
+use relay_utils::FailedClient;
use sp_core::Bytes;
use sp_runtime::{
traits::{Hash, Header as HeaderT},
@@ -274,7 +275,7 @@ async fn run_loop_iteration>(
let (is_updated, updated_transaction) = update_transaction_tip::(
&client,
&transaction_params,
- HeaderId(*context.best_header.number(), context.best_header.hash()),
+ context.best_header.id(),
original_transaction,
context.tip_step,
context.tip_limit,
diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs
index 5619645d0a..e5309bb54e 100644
--- a/bridges/relays/client-substrate/src/client.rs
+++ b/bridges/relays/client-substrate/src/client.rs
@@ -25,6 +25,7 @@ use crate::{
use async_std::sync::{Arc, Mutex};
use async_trait::async_trait;
+use bp_runtime::HeaderIdProvider;
use codec::{Decode, Encode};
use frame_system::AccountInfo;
use futures::{SinkExt, StreamExt};
@@ -33,10 +34,10 @@ use jsonrpsee::{
types::params::ParamsSer,
ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder},
};
-use num_traits::{Bounded, CheckedSub, One, Zero};
+use num_traits::{Bounded, Zero};
use pallet_balances::AccountData;
use pallet_transaction_payment::InclusionFee;
-use relay_utils::{relay_loop::RECONNECT_DELAY, HeaderId};
+use relay_utils::relay_loop::RECONNECT_DELAY;
use sp_core::{
storage::{StorageData, StorageKey},
Bytes, Hasher,
@@ -484,14 +485,11 @@ impl Client {
let best_header = self.best_header().await?;
// By using parent of best block here, we are protecing again best-block reorganizations.
- // E.g. transaction my have been submitted when the best block was `A[num=100]`. Then it has
- // been changed to `B[num=100]`. Hash of `A` has been included into transaction signature
- // payload. So when signature will be checked, the check will fail and transaction will be
- // dropped from the pool.
- let best_header_id = match best_header.number().checked_sub(&One::one()) {
- Some(parent_block_number) => HeaderId(parent_block_number, *best_header.parent_hash()),
- None => HeaderId(*best_header.number(), best_header.hash()),
- };
+ // E.g. transaction may have been submitted when the best block was `A[num=100]`. Then it
+ // has been changed to `B[num=100]`. Hash of `A` has been included into transaction
+ // signature payload. So when signature will be checked, the check will fail and transaction
+ // will be dropped from the pool.
+ let best_header_id = best_header.parent_id().unwrap_or_else(|| best_header.id());
self.jsonrpsee_execute(move |client| async move {
let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?;
@@ -524,7 +522,7 @@ impl Client {
let _guard = self.submit_signed_extrinsic_lock.lock().await;
let transaction_nonce = self.next_account_index(extrinsic_signer).await?;
let best_header = self.best_header().await?;
- let best_header_id = HeaderId(*best_header.number(), best_header.hash());
+ let best_header_id = best_header.id();
let subscription = self
.jsonrpsee_execute(move |client| async move {
let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?;
diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs
index 8ed8367d35..2daa41fc28 100644
--- a/bridges/relays/lib-substrate-relay/src/messages_source.rs
+++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs
@@ -34,7 +34,7 @@ use bp_messages::{
InboundMessageDetails, LaneId, MessageData, MessageNonce, MessagesOperatingMode,
OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState,
};
-use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode};
+use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, HeaderIdProvider};
use bridge_runtime_common::messages::{
source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
};
@@ -510,13 +510,12 @@ where
let self_best_finalized_header_hash = self_client.best_finalized_header_hash().await?;
let self_best_finalized_header =
self_client.header_by_hash(self_best_finalized_header_hash).await?;
- let self_best_finalized_id =
- HeaderId(*self_best_finalized_header.number(), self_best_finalized_header_hash);
+ let self_best_finalized_id = self_best_finalized_header.id();
// now let's read our best header on **this** chain
let self_best_header = self_client.best_header().await?;
let self_best_hash = self_best_header.hash();
- let self_best_id = HeaderId(*self_best_header.number(), self_best_hash);
+ let self_best_id = self_best_header.id();
// now let's read id of best finalized peer header at our best finalized block
let peer_on_self_best_finalized_id =
@@ -532,7 +531,7 @@ where
Some(peer_client) => {
let actual_peer_on_self_best_finalized =
peer_client.header_by_number(peer_on_self_best_finalized_id.0).await?;
- HeaderId(peer_on_self_best_finalized_id.0, actual_peer_on_self_best_finalized.hash())
+ actual_peer_on_self_best_finalized.id()
},
None => peer_on_self_best_finalized_id,
};
diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs
index f25d3b7694..77d80bc79b 100644
--- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs
+++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs
@@ -32,6 +32,7 @@ use async_std::{
};
use async_trait::async_trait;
use bp_polkadot_core::parachains::ParaHash;
+use bp_runtime::HeaderIdProvider;
use futures::{select, FutureExt};
use num_traits::Zero;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
@@ -43,7 +44,6 @@ use relay_substrate_client::{
use relay_utils::{
metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, HeaderId,
};
-use sp_runtime::traits::Header as HeaderT;
use std::fmt::Debug;
/// On-demand Substrate <-> Substrate parachain finality relay.
@@ -387,8 +387,7 @@ where
let best_finalized_relay_header =
source.client().best_finalized_header().await.map_err(map_source_err)?;
- let best_finalized_relay_block_id =
- HeaderId(*best_finalized_relay_header.number(), best_finalized_relay_header.hash());
+ let best_finalized_relay_block_id = best_finalized_relay_header.id();
let para_header_at_source = source
.on_chain_parachain_header(
best_finalized_relay_block_id,
@@ -396,7 +395,7 @@ where
)
.await
.map_err(map_source_err)?
- .map(|h| HeaderId(*h.number(), h.hash()));
+ .map(|h| h.id());
let relay_header_at_source = best_finalized_relay_block_id.0;
let relay_header_at_target =
@@ -412,7 +411,7 @@ where
.on_chain_parachain_header(relay_header_at_target, P::SOURCE_PARACHAIN_PARA_ID.into())
.await
.map_err(map_source_err)?
- .map(|h| HeaderId(*h.number(), h.hash()));
+ .map(|h| h.id());
Ok(RelayData {
required_para_header: required_header_number,
diff --git a/bridges/relays/lib-substrate-relay/src/parachains/target.rs b/bridges/relays/lib-substrate-relay/src/parachains/target.rs
index d26894b9bd..43168f2c85 100644
--- a/bridges/relays/lib-substrate-relay/src/parachains/target.rs
+++ b/bridges/relays/lib-substrate-relay/src/parachains/target.rs
@@ -29,6 +29,7 @@ use bp_parachains::{
BestParaHeadHash,
};
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
+use bp_runtime::HeaderIdProvider;
use codec::{Decode, Encode};
use parachains_relay::{
parachains_loop::TargetClient, parachains_loop_metrics::ParachainsLoopMetrics,
@@ -90,8 +91,7 @@ where
{
async fn best_block(&self) -> Result, Self::Error> {
let best_header = self.client.best_header().await?;
- let best_hash = best_header.hash();
- let best_id = HeaderId(*best_header.number(), best_hash);
+ let best_id = best_header.id();
Ok(best_id)
}