mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 03:31:10 +00:00
Add another condition to the reject-obsolete-parachain-heads extension (#1505)
* add another condition to the reject-obsolete-parachain-heads extension * add tracing to obsolete-tx-extensions * fix tests * extension_rejects_header_from_new_relay_block_with_same_hash * fmt * fix benchmarks
This commit is contained in:
committed by
Bastian Köcher
parent
e9d7adf8fd
commit
ea1f46ff45
@@ -1035,6 +1035,7 @@ impl_runtime_apis! {
|
|||||||
pallet_bridge_parachains::RelayBlockNumber,
|
pallet_bridge_parachains::RelayBlockNumber,
|
||||||
pallet_bridge_parachains::RelayBlockHash,
|
pallet_bridge_parachains::RelayBlockHash,
|
||||||
bp_polkadot_core::parachains::ParaHeadsProof,
|
bp_polkadot_core::parachains::ParaHeadsProof,
|
||||||
|
Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>,
|
||||||
) {
|
) {
|
||||||
bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof::<Runtime, WithRialtoParachainsInstance>(
|
bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof::<Runtime, WithRialtoParachainsInstance>(
|
||||||
parachains,
|
parachains,
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ macro_rules! declare_bridge_reject_obsolete_messages {
|
|||||||
|
|
||||||
let inbound_lane_data = pallet_bridge_messages::InboundLanes::<$runtime, $instance>::get(&proof.lane);
|
let inbound_lane_data = pallet_bridge_messages::InboundLanes::<$runtime, $instance>::get(&proof.lane);
|
||||||
if proof.nonces_end <= inbound_lane_data.last_delivered_nonce() {
|
if proof.nonces_end <= inbound_lane_data.last_delivered_nonce() {
|
||||||
|
log::trace!(
|
||||||
|
target: pallet_bridge_messages::LOG_TARGET,
|
||||||
|
"Rejecting obsolete messages delivery transaction: lane {:?}, bundled {:?}, best {:?}",
|
||||||
|
proof.lane,
|
||||||
|
proof.nonces_end,
|
||||||
|
inbound_lane_data.last_delivered_nonce(),
|
||||||
|
);
|
||||||
|
|
||||||
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into();
|
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +92,14 @@ macro_rules! declare_bridge_reject_obsolete_messages {
|
|||||||
|
|
||||||
let outbound_lane_data = pallet_bridge_messages::OutboundLanes::<$runtime, $instance>::get(&proof.lane);
|
let outbound_lane_data = pallet_bridge_messages::OutboundLanes::<$runtime, $instance>::get(&proof.lane);
|
||||||
if latest_delivered_nonce <= outbound_lane_data.latest_received_nonce {
|
if latest_delivered_nonce <= outbound_lane_data.latest_received_nonce {
|
||||||
|
log::trace!(
|
||||||
|
target: pallet_bridge_messages::LOG_TARGET,
|
||||||
|
"Rejecting obsolete messages confirmation transaction: lane {:?}, bundled {:?}, best {:?}",
|
||||||
|
proof.lane,
|
||||||
|
latest_delivered_nonce,
|
||||||
|
outbound_lane_data.latest_received_nonce,
|
||||||
|
);
|
||||||
|
|
||||||
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into();
|
return sp_runtime::transaction_validity::InvalidTransaction::Stale.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
use crate::messages_benchmarking::{grow_trie, insert_header_to_grandpa_pallet};
|
use crate::messages_benchmarking::{grow_trie, insert_header_to_grandpa_pallet};
|
||||||
|
|
||||||
use bp_parachains::parachain_head_storage_key_at_source;
|
use bp_parachains::parachain_head_storage_key_at_source;
|
||||||
use bp_polkadot_core::parachains::{ParaHead, ParaHeadsProof, ParaId};
|
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
|
||||||
use bp_runtime::StorageProofSize;
|
use bp_runtime::StorageProofSize;
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
use frame_support::traits::Get;
|
use frame_support::traits::Get;
|
||||||
@@ -37,7 +37,7 @@ pub fn prepare_parachain_heads_proof<R, PI>(
|
|||||||
parachains: &[ParaId],
|
parachains: &[ParaId],
|
||||||
parachain_head_size: u32,
|
parachain_head_size: u32,
|
||||||
size: StorageProofSize,
|
size: StorageProofSize,
|
||||||
) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof)
|
) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>)
|
||||||
where
|
where
|
||||||
R: pallet_bridge_parachains::Config<PI>
|
R: pallet_bridge_parachains::Config<PI>
|
||||||
+ pallet_bridge_grandpa::Config<R::BridgesGrandpaPalletInstance>,
|
+ pallet_bridge_grandpa::Config<R::BridgesGrandpaPalletInstance>,
|
||||||
@@ -48,6 +48,7 @@ where
|
|||||||
let parachain_head = ParaHead(vec![0u8; parachain_head_size as usize]);
|
let parachain_head = ParaHead(vec![0u8; parachain_head_size as usize]);
|
||||||
|
|
||||||
// insert all heads to the trie
|
// insert all heads to the trie
|
||||||
|
let mut parachain_heads = Vec::with_capacity(parachains.len());
|
||||||
let mut storage_keys = Vec::with_capacity(parachains.len());
|
let mut storage_keys = Vec::with_capacity(parachains.len());
|
||||||
let mut state_root = Default::default();
|
let mut state_root = Default::default();
|
||||||
let mut mdb = MemoryDB::default();
|
let mut mdb = MemoryDB::default();
|
||||||
@@ -62,6 +63,7 @@ where
|
|||||||
.map_err(|_| "TrieMut::insert has failed")
|
.map_err(|_| "TrieMut::insert has failed")
|
||||||
.expect("TrieMut::insert should not fail in benchmarks");
|
.expect("TrieMut::insert should not fail in benchmarks");
|
||||||
storage_keys.push(storage_key);
|
storage_keys.push(storage_key);
|
||||||
|
parachain_heads.push((*parachain, parachain_head.hash()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state_root = grow_trie(state_root, &mut mdb, size);
|
state_root = grow_trie(state_root, &mut mdb, size);
|
||||||
@@ -76,5 +78,5 @@ where
|
|||||||
let (relay_block_number, relay_block_hash) =
|
let (relay_block_number, relay_block_hash) =
|
||||||
insert_header_to_grandpa_pallet::<R, R::BridgesGrandpaPalletInstance>(state_root);
|
insert_header_to_grandpa_pallet::<R, R::BridgesGrandpaPalletInstance>(state_root);
|
||||||
|
|
||||||
(relay_block_number, relay_block_hash, ParaHeadsProof(proof))
|
(relay_block_number, relay_block_hash, ParaHeadsProof(proof), parachain_heads)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,13 @@ macro_rules! declare_bridge_reject_obsolete_grandpa_header {
|
|||||||
if best_finalized_number < bundled_block_number {
|
if best_finalized_number < bundled_block_number {
|
||||||
Ok(sp_runtime::transaction_validity::ValidTransaction::default())
|
Ok(sp_runtime::transaction_validity::ValidTransaction::default())
|
||||||
} else {
|
} else {
|
||||||
|
log::trace!(
|
||||||
|
target: $crate::LOG_TARGET,
|
||||||
|
"Rejecting obsolete bridged header: bundled {:?}, best {:?}",
|
||||||
|
bundled_block_number,
|
||||||
|
best_finalized_number,
|
||||||
|
);
|
||||||
|
|
||||||
sp_runtime::transaction_validity::InvalidTransaction::Stale.into()
|
sp_runtime::transaction_validity::InvalidTransaction::Stale.into()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pub use pallet::*;
|
|||||||
pub use weights::WeightInfo;
|
pub use weights::WeightInfo;
|
||||||
|
|
||||||
/// The target that will be used when publishing logs related to this pallet.
|
/// The target that will be used when publishing logs related to this pallet.
|
||||||
const LOG_TARGET: &str = "runtime::bridge-grandpa";
|
pub const LOG_TARGET: &str = "runtime::bridge-grandpa";
|
||||||
|
|
||||||
/// Block number of the bridged chain.
|
/// Block number of the bridged chain.
|
||||||
pub type BridgedBlockNumber<T, I> = BlockNumberOf<<T as Config<I>>::BridgedChain>;
|
pub type BridgedBlockNumber<T, I> = BlockNumberOf<<T as Config<I>>::BridgedChain>;
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ mod mock;
|
|||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
/// The target that will be used when publishing logs related to this pallet.
|
/// The target that will be used when publishing logs related to this pallet.
|
||||||
const LOG_TARGET: &str = "runtime::bridge-messages";
|
pub const LOG_TARGET: &str = "runtime::bridge-messages";
|
||||||
|
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use crate::{
|
|||||||
RelayBlockNumber,
|
RelayBlockNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId};
|
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
|
||||||
use bp_runtime::StorageProofSize;
|
use bp_runtime::StorageProofSize;
|
||||||
use frame_benchmarking::{account, benchmarks_instance_pallet};
|
use frame_benchmarking::{account, benchmarks_instance_pallet};
|
||||||
use frame_system::RawOrigin;
|
use frame_system::RawOrigin;
|
||||||
@@ -37,7 +37,7 @@ pub trait Config<I: 'static>: crate::Config<I> {
|
|||||||
parachains: &[ParaId],
|
parachains: &[ParaId],
|
||||||
parachain_head_size: u32,
|
parachain_head_size: u32,
|
||||||
proof_size: StorageProofSize,
|
proof_size: StorageProofSize,
|
||||||
) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof);
|
) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>);
|
||||||
}
|
}
|
||||||
|
|
||||||
benchmarks_instance_pallet! {
|
benchmarks_instance_pallet! {
|
||||||
@@ -57,13 +57,13 @@ benchmarks_instance_pallet! {
|
|||||||
|
|
||||||
let sender = account("sender", 0, 0);
|
let sender = account("sender", 0, 0);
|
||||||
let parachains = (1..=p).map(ParaId).collect::<Vec<_>>();
|
let parachains = (1..=p).map(ParaId).collect::<Vec<_>>();
|
||||||
let (relay_block_number, relay_block_hash, parachain_heads_proof) = T::prepare_parachain_heads_proof(
|
let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof(
|
||||||
¶chains,
|
¶chains,
|
||||||
DEFAULT_PARACHAIN_HEAD_SIZE,
|
DEFAULT_PARACHAIN_HEAD_SIZE,
|
||||||
StorageProofSize::Minimal(0),
|
StorageProofSize::Minimal(0),
|
||||||
);
|
);
|
||||||
let at_relay_block = (relay_block_number, relay_block_hash);
|
let at_relay_block = (relay_block_number, relay_block_hash);
|
||||||
}: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains.clone(), parachain_heads_proof)
|
}: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof)
|
||||||
verify {
|
verify {
|
||||||
for parachain in parachains {
|
for parachain in parachains {
|
||||||
assert!(crate::Pallet::<T, I>::best_parachain_head(parachain).is_some());
|
assert!(crate::Pallet::<T, I>::best_parachain_head(parachain).is_some());
|
||||||
@@ -74,13 +74,13 @@ benchmarks_instance_pallet! {
|
|||||||
submit_parachain_heads_with_1kb_proof {
|
submit_parachain_heads_with_1kb_proof {
|
||||||
let sender = account("sender", 0, 0);
|
let sender = account("sender", 0, 0);
|
||||||
let parachains = vec![ParaId(1)];
|
let parachains = vec![ParaId(1)];
|
||||||
let (relay_block_number, relay_block_hash, parachain_heads_proof) = T::prepare_parachain_heads_proof(
|
let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof(
|
||||||
¶chains,
|
¶chains,
|
||||||
DEFAULT_PARACHAIN_HEAD_SIZE,
|
DEFAULT_PARACHAIN_HEAD_SIZE,
|
||||||
StorageProofSize::HasExtraNodes(1024),
|
StorageProofSize::HasExtraNodes(1024),
|
||||||
);
|
);
|
||||||
let at_relay_block = (relay_block_number, relay_block_hash);
|
let at_relay_block = (relay_block_number, relay_block_hash);
|
||||||
}: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains.clone(), parachain_heads_proof)
|
}: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof)
|
||||||
verify {
|
verify {
|
||||||
for parachain in parachains {
|
for parachain in parachains {
|
||||||
assert!(crate::Pallet::<T, I>::best_parachain_head(parachain).is_some());
|
assert!(crate::Pallet::<T, I>::best_parachain_head(parachain).is_some());
|
||||||
@@ -91,13 +91,13 @@ benchmarks_instance_pallet! {
|
|||||||
submit_parachain_heads_with_16kb_proof {
|
submit_parachain_heads_with_16kb_proof {
|
||||||
let sender = account("sender", 0, 0);
|
let sender = account("sender", 0, 0);
|
||||||
let parachains = vec![ParaId(1)];
|
let parachains = vec![ParaId(1)];
|
||||||
let (relay_block_number, relay_block_hash, parachain_heads_proof) = T::prepare_parachain_heads_proof(
|
let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof(
|
||||||
¶chains,
|
¶chains,
|
||||||
DEFAULT_PARACHAIN_HEAD_SIZE,
|
DEFAULT_PARACHAIN_HEAD_SIZE,
|
||||||
StorageProofSize::HasExtraNodes(16 * 1024),
|
StorageProofSize::HasExtraNodes(16 * 1024),
|
||||||
);
|
);
|
||||||
let at_relay_block = (relay_block_number, relay_block_hash);
|
let at_relay_block = (relay_block_number, relay_block_hash);
|
||||||
}: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains.clone(), parachain_heads_proof)
|
}: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof)
|
||||||
verify {
|
verify {
|
||||||
for parachain in parachains {
|
for parachain in parachains {
|
||||||
assert!(crate::Pallet::<T, I>::best_parachain_head(parachain).is_some());
|
assert!(crate::Pallet::<T, I>::best_parachain_head(parachain).is_some());
|
||||||
|
|||||||
@@ -72,15 +72,34 @@ macro_rules! declare_bridge_reject_obsolete_parachain_header {
|
|||||||
ref parachains,
|
ref parachains,
|
||||||
..
|
..
|
||||||
}) if parachains.len() == 1 => {
|
}) if parachains.len() == 1 => {
|
||||||
let parachain = parachains.get(0).expect("verified by match condition; qed");
|
let (parachain, parachain_head_hash) = parachains.get(0).expect("verified by match condition; qed");
|
||||||
|
|
||||||
let bundled_relay_block_number = at_relay_block.0;
|
let bundled_relay_block_number = at_relay_block.0;
|
||||||
|
|
||||||
let best_parachain_head = $crate::BestParaHeads::<$runtime, $instance>::get(parachain);
|
let best_parachain_head = $crate::BestParaHeads::<$runtime, $instance>::get(parachain);
|
||||||
|
|
||||||
match best_parachain_head {
|
match best_parachain_head {
|
||||||
Some(best_parachain_head) if best_parachain_head.at_relay_block_number
|
Some(best_parachain_head) if best_parachain_head.at_relay_block_number
|
||||||
>= bundled_relay_block_number =>
|
>= bundled_relay_block_number => {
|
||||||
sp_runtime::transaction_validity::InvalidTransaction::Stale.into(),
|
log::trace!(
|
||||||
|
target: $crate::LOG_TARGET,
|
||||||
|
"Rejecting obsolete parachain-head {:?} transaction: bundled relay block number: \
|
||||||
|
{:?} best relay block number: {:?}",
|
||||||
|
parachain,
|
||||||
|
bundled_relay_block_number,
|
||||||
|
best_parachain_head.at_relay_block_number,
|
||||||
|
);
|
||||||
|
sp_runtime::transaction_validity::InvalidTransaction::Stale.into()
|
||||||
|
}
|
||||||
|
Some(best_parachain_head) if best_parachain_head.head_hash == *parachain_head_hash => {
|
||||||
|
log::trace!(
|
||||||
|
target: $crate::LOG_TARGET,
|
||||||
|
"Rejecting obsolete parachain-head {:?} transaction: head hash {:?}",
|
||||||
|
parachain,
|
||||||
|
best_parachain_head.head_hash,
|
||||||
|
);
|
||||||
|
sp_runtime::transaction_validity::InvalidTransaction::Stale.into()
|
||||||
|
}
|
||||||
_ => Ok(sp_runtime::transaction_validity::ValidTransaction::default()),
|
_ => Ok(sp_runtime::transaction_validity::ValidTransaction::default()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -118,7 +137,7 @@ mod tests {
|
|||||||
mock::{run_test, Call, TestRuntime},
|
mock::{run_test, Call, TestRuntime},
|
||||||
BestParaHead, BestParaHeads, RelayBlockNumber,
|
BestParaHead, BestParaHeads, RelayBlockNumber,
|
||||||
};
|
};
|
||||||
use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId};
|
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
|
||||||
use frame_support::weights::{DispatchClass, DispatchInfo, Pays};
|
use frame_support::weights::{DispatchClass, DispatchInfo, Pays};
|
||||||
use sp_runtime::traits::SignedExtension;
|
use sp_runtime::traits::SignedExtension;
|
||||||
|
|
||||||
@@ -127,7 +146,10 @@ mod tests {
|
|||||||
Call::Parachains => ()
|
Call::Parachains => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_submit_parachain_heads(num: RelayBlockNumber, parachains: Vec<ParaId>) -> bool {
|
fn validate_submit_parachain_heads(
|
||||||
|
num: RelayBlockNumber,
|
||||||
|
parachains: Vec<(ParaId, ParaHash)>,
|
||||||
|
) -> bool {
|
||||||
BridgeRejectObsoleteParachainHeader
|
BridgeRejectObsoleteParachainHeader
|
||||||
.validate(
|
.validate(
|
||||||
&42,
|
&42,
|
||||||
@@ -147,29 +169,39 @@ mod tests {
|
|||||||
ParaId(1),
|
ParaId(1),
|
||||||
BestParaHead {
|
BestParaHead {
|
||||||
at_relay_block_number: 10,
|
at_relay_block_number: 10,
|
||||||
head_hash: Default::default(),
|
head_hash: [1u8; 32].into(),
|
||||||
next_imported_hash_position: 0,
|
next_imported_hash_position: 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn extension_rejects_obsolete_header() {
|
fn extension_rejects_header_from_the_obsolete_relay_block() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// when current best finalized is #10 and we're trying to import header#5 => tx is
|
// when current best finalized is #10 and we're trying to import header#5 => tx is
|
||||||
// rejected
|
// rejected
|
||||||
sync_to_relay_header_10();
|
sync_to_relay_header_10();
|
||||||
assert!(!validate_submit_parachain_heads(5, vec![ParaId(1)]));
|
assert!(!validate_submit_parachain_heads(5, vec![(ParaId(1), [1u8; 32].into())]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn extension_rejects_same_header() {
|
fn extension_rejects_header_from_the_same_relay_block() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// when current best finalized is #10 and we're trying to import header#10 => tx is
|
// when current best finalized is #10 and we're trying to import header#10 => tx is
|
||||||
// rejected
|
// rejected
|
||||||
sync_to_relay_header_10();
|
sync_to_relay_header_10();
|
||||||
assert!(!validate_submit_parachain_heads(10, vec![ParaId(1)]));
|
assert!(!validate_submit_parachain_heads(10, vec![(ParaId(1), [1u8; 32].into())]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extension_rejects_header_from_new_relay_block_with_same_hash() {
|
||||||
|
run_test(|| {
|
||||||
|
// when current best finalized is #10 and we're trying to import header#10 => tx is
|
||||||
|
// rejected
|
||||||
|
sync_to_relay_header_10();
|
||||||
|
assert!(!validate_submit_parachain_heads(20, vec![(ParaId(1), [1u8; 32].into())]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +211,7 @@ mod tests {
|
|||||||
// when current best finalized is #10 and we're trying to import header#15 => tx is
|
// when current best finalized is #10 and we're trying to import header#15 => tx is
|
||||||
// accepted
|
// accepted
|
||||||
sync_to_relay_header_10();
|
sync_to_relay_header_10();
|
||||||
assert!(validate_submit_parachain_heads(15, vec![ParaId(1)]));
|
assert!(validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())]));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +221,10 @@ mod tests {
|
|||||||
// when current best finalized is #10 and we're trying to import header#5, but another
|
// when current best finalized is #10 and we're trying to import header#5, but another
|
||||||
// parachain head is also supplied => tx is accepted
|
// parachain head is also supplied => tx is accepted
|
||||||
sync_to_relay_header_10();
|
sync_to_relay_header_10();
|
||||||
assert!(validate_submit_parachain_heads(5, vec![ParaId(1), ParaId(2)]));
|
assert!(validate_submit_parachain_heads(
|
||||||
|
5,
|
||||||
|
vec![(ParaId(1), [1u8; 32].into()), (ParaId(2), [1u8; 32].into())]
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ mod extension;
|
|||||||
mod mock;
|
mod mock;
|
||||||
|
|
||||||
/// The target that will be used when publishing logs related to this pallet.
|
/// The target that will be used when publishing logs related to this pallet.
|
||||||
const LOG_TARGET: &str = "runtime::bridge-parachains";
|
pub const LOG_TARGET: &str = "runtime::bridge-parachains";
|
||||||
|
|
||||||
/// Block hash of the bridged relay chain.
|
/// Block hash of the bridged relay chain.
|
||||||
pub type RelayBlockHash = bp_polkadot_core::Hash;
|
pub type RelayBlockHash = bp_polkadot_core::Hash;
|
||||||
@@ -209,7 +209,7 @@ pub mod pallet {
|
|||||||
pub fn submit_parachain_heads(
|
pub fn submit_parachain_heads(
|
||||||
_origin: OriginFor<T>,
|
_origin: OriginFor<T>,
|
||||||
at_relay_block: (RelayBlockNumber, RelayBlockHash),
|
at_relay_block: (RelayBlockNumber, RelayBlockHash),
|
||||||
parachains: Vec<ParaId>,
|
parachains: Vec<(ParaId, ParaHash)>,
|
||||||
parachain_heads_proof: ParaHeadsProof,
|
parachain_heads_proof: ParaHeadsProof,
|
||||||
) -> DispatchResultWithPostInfo {
|
) -> DispatchResultWithPostInfo {
|
||||||
Self::ensure_not_halted().map_err(Error::<T, I>::BridgeModule)?;
|
Self::ensure_not_halted().map_err(Error::<T, I>::BridgeModule)?;
|
||||||
@@ -235,7 +235,7 @@ pub mod pallet {
|
|||||||
relay_block_hash,
|
relay_block_hash,
|
||||||
sp_trie::StorageProof::new(parachain_heads_proof.0),
|
sp_trie::StorageProof::new(parachain_heads_proof.0),
|
||||||
move |storage| {
|
move |storage| {
|
||||||
for parachain in parachains {
|
for (parachain, parachain_head_hash) in parachains {
|
||||||
// if we're not tracking this parachain, we'll just ignore its head proof here
|
// if we're not tracking this parachain, we'll just ignore its head proof here
|
||||||
if !T::TrackedParachains::contains(¶chain) {
|
if !T::TrackedParachains::contains(¶chain) {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
@@ -272,12 +272,27 @@ pub mod pallet {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// if relayer has specified invalid parachain head hash, ignore the head
|
||||||
|
// (this isn't strictly necessary, but better safe than sorry)
|
||||||
|
let actual_parachain_head_hash = parachain_head.hash();
|
||||||
|
if parachain_head_hash != actual_parachain_head_hash {
|
||||||
|
log::trace!(
|
||||||
|
target: LOG_TARGET,
|
||||||
|
"The submitter has specified invalid parachain {:?} head hash: {:?} vs {:?}",
|
||||||
|
parachain,
|
||||||
|
parachain_head_hash,
|
||||||
|
actual_parachain_head_hash,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let prune_happened: Result<_, ()> = BestParaHeads::<T, I>::try_mutate(parachain, |stored_best_head| {
|
let prune_happened: Result<_, ()> = BestParaHeads::<T, I>::try_mutate(parachain, |stored_best_head| {
|
||||||
let artifacts = Pallet::<T, I>::update_parachain_head(
|
let artifacts = Pallet::<T, I>::update_parachain_head(
|
||||||
parachain,
|
parachain,
|
||||||
stored_best_head.take(),
|
stored_best_head.take(),
|
||||||
relay_block_number,
|
relay_block_number,
|
||||||
parachain_head,
|
parachain_head,
|
||||||
|
parachain_head_hash,
|
||||||
)?;
|
)?;
|
||||||
*stored_best_head = Some(artifacts.best_head);
|
*stored_best_head = Some(artifacts.best_head);
|
||||||
Ok(artifacts.prune_happened)
|
Ok(artifacts.prune_happened)
|
||||||
@@ -364,10 +379,10 @@ pub mod pallet {
|
|||||||
stored_best_head: Option<BestParaHead>,
|
stored_best_head: Option<BestParaHead>,
|
||||||
updated_at_relay_block_number: RelayBlockNumber,
|
updated_at_relay_block_number: RelayBlockNumber,
|
||||||
updated_head: ParaHead,
|
updated_head: ParaHead,
|
||||||
|
updated_head_hash: ParaHash,
|
||||||
) -> Result<UpdateParachainHeadArtifacts, ()> {
|
) -> Result<UpdateParachainHeadArtifacts, ()> {
|
||||||
// check if head has been already updated at better relay chain block. Without this
|
// check if head has been already updated at better relay chain block. Without this
|
||||||
// check, we may import heads in random order
|
// check, we may import heads in random order
|
||||||
let updated_head_hash = updated_head.hash();
|
|
||||||
let next_imported_hash_position = match stored_best_head {
|
let next_imported_hash_position = match stored_best_head {
|
||||||
Some(stored_best_head)
|
Some(stored_best_head)
|
||||||
if stored_best_head.at_relay_block_number <= updated_at_relay_block_number =>
|
if stored_best_head.at_relay_block_number <= updated_at_relay_block_number =>
|
||||||
@@ -376,7 +391,7 @@ pub mod pallet {
|
|||||||
if updated_head_hash == stored_best_head.head_hash {
|
if updated_head_hash == stored_best_head.head_hash {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"The head of parachain {:?} can't be updated to {}, because it has been already updated\
|
"The head of parachain {:?} can't be updated to {}, because it has been already updated \
|
||||||
to the same value at previous relay chain block: {} < {}",
|
to the same value at previous relay chain block: {} < {}",
|
||||||
parachain,
|
parachain,
|
||||||
updated_head_hash,
|
updated_head_hash,
|
||||||
@@ -392,7 +407,7 @@ pub mod pallet {
|
|||||||
Some(stored_best_head) => {
|
Some(stored_best_head) => {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
target: LOG_TARGET,
|
target: LOG_TARGET,
|
||||||
"The head of parachain {:?} can't be updated to {}, because it has been already updated\
|
"The head of parachain {:?} can't be updated to {}, because it has been already updated \
|
||||||
to {} at better relay chain block: {} > {}",
|
to {} at better relay chain block: {} > {}",
|
||||||
parachain,
|
parachain,
|
||||||
updated_head_hash,
|
updated_head_hash,
|
||||||
@@ -530,7 +545,8 @@ mod tests {
|
|||||||
|
|
||||||
fn prepare_parachain_heads_proof(
|
fn prepare_parachain_heads_proof(
|
||||||
heads: Vec<(u32, ParaHead)>,
|
heads: Vec<(u32, ParaHead)>,
|
||||||
) -> (RelayBlockHash, ParaHeadsProof) {
|
) -> (RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) {
|
||||||
|
let mut parachains = Vec::with_capacity(heads.len());
|
||||||
let mut root = Default::default();
|
let mut root = Default::default();
|
||||||
let mut mdb = MemoryDB::default();
|
let mut mdb = MemoryDB::default();
|
||||||
{
|
{
|
||||||
@@ -541,6 +557,7 @@ mod tests {
|
|||||||
trie.insert(&storage_key.0, &head.encode())
|
trie.insert(&storage_key.0, &head.encode())
|
||||||
.map_err(|_| "TrieMut::insert has failed")
|
.map_err(|_| "TrieMut::insert has failed")
|
||||||
.expect("TrieMut::insert should not fail in tests");
|
.expect("TrieMut::insert should not fail in tests");
|
||||||
|
parachains.push((ParaId(parachain), head.hash()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,7 +568,7 @@ mod tests {
|
|||||||
.expect("record_all_keys should not fail in benchmarks");
|
.expect("record_all_keys should not fail in benchmarks");
|
||||||
let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect();
|
let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect();
|
||||||
|
|
||||||
(root, ParaHeadsProof(storage_proof))
|
(root, ParaHeadsProof(storage_proof), parachains)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_best_head(parachain: u32) -> BestParaHead {
|
fn initial_best_head(parachain: u32) -> BestParaHead {
|
||||||
@@ -573,12 +590,13 @@ mod tests {
|
|||||||
fn import_parachain_1_head(
|
fn import_parachain_1_head(
|
||||||
relay_chain_block: RelayBlockNumber,
|
relay_chain_block: RelayBlockNumber,
|
||||||
relay_state_root: RelayBlockHash,
|
relay_state_root: RelayBlockHash,
|
||||||
|
parachains: Vec<(ParaId, ParaHash)>,
|
||||||
proof: ParaHeadsProof,
|
proof: ParaHeadsProof,
|
||||||
) -> DispatchResultWithPostInfo {
|
) -> DispatchResultWithPostInfo {
|
||||||
Pallet::<TestRuntime>::submit_parachain_heads(
|
Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(relay_chain_block, test_relay_header(relay_chain_block, relay_state_root).hash()),
|
(relay_chain_block, test_relay_header(relay_chain_block, relay_state_root).hash()),
|
||||||
vec![ParaId(1)],
|
parachains,
|
||||||
proof,
|
proof,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -595,7 +613,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn submit_parachain_heads_checks_operating_mode() {
|
fn submit_parachain_heads_checks_operating_mode() {
|
||||||
let (state_root, proof) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
|
let (state_root, proof, parachains) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
|
||||||
|
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
initialize(state_root);
|
initialize(state_root);
|
||||||
@@ -606,7 +625,7 @@ mod tests {
|
|||||||
Pallet::<TestRuntime>::submit_parachain_heads(
|
Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(0, test_relay_header(0, state_root).hash()),
|
(0, test_relay_header(0, state_root).hash()),
|
||||||
vec![ParaId(1), ParaId(2), ParaId(3)],
|
parachains.clone(),
|
||||||
proof.clone(),
|
proof.clone(),
|
||||||
),
|
),
|
||||||
Error::<TestRuntime>::BridgeModule(OwnedBridgeModuleError::Halted)
|
Error::<TestRuntime>::BridgeModule(OwnedBridgeModuleError::Halted)
|
||||||
@@ -617,7 +636,7 @@ mod tests {
|
|||||||
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(0, test_relay_header(0, state_root).hash()),
|
(0, test_relay_header(0, state_root).hash()),
|
||||||
vec![ParaId(1)],
|
parachains,
|
||||||
proof,
|
proof,
|
||||||
),);
|
),);
|
||||||
});
|
});
|
||||||
@@ -625,7 +644,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn imports_initial_parachain_heads() {
|
fn imports_initial_parachain_heads() {
|
||||||
let (state_root, proof) =
|
let (state_root, proof, parachains) =
|
||||||
prepare_parachain_heads_proof(vec![(1, head_data(1, 0)), (3, head_data(3, 10))]);
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 0)), (3, head_data(3, 10))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
initialize(state_root);
|
initialize(state_root);
|
||||||
@@ -634,7 +653,7 @@ mod tests {
|
|||||||
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(0, test_relay_header(0, state_root).hash()),
|
(0, test_relay_header(0, state_root).hash()),
|
||||||
vec![ParaId(1), ParaId(2), ParaId(3)],
|
parachains,
|
||||||
proof,
|
proof,
|
||||||
),);
|
),);
|
||||||
|
|
||||||
@@ -667,12 +686,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn imports_parachain_heads_is_able_to_progress() {
|
fn imports_parachain_heads_is_able_to_progress() {
|
||||||
let (state_root_5, proof_5) = prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
let (state_root_5, proof_5, parachains_5) =
|
||||||
let (state_root_10, proof_10) = prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
||||||
|
let (state_root_10, proof_10, parachains_10) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// start with relay block #0 and import head#5 of parachain#1
|
// start with relay block #0 and import head#5 of parachain#1
|
||||||
initialize(state_root_5);
|
initialize(state_root_5);
|
||||||
assert_ok!(import_parachain_1_head(0, state_root_5, proof_5));
|
assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
||||||
Some(BestParaHead {
|
Some(BestParaHead {
|
||||||
@@ -692,7 +713,7 @@ mod tests {
|
|||||||
|
|
||||||
// import head#10 of parachain#1 at relay block #1
|
// import head#10 of parachain#1 at relay block #1
|
||||||
proceed(1, state_root_10);
|
proceed(1, state_root_10);
|
||||||
assert_ok!(import_parachain_1_head(1, state_root_10, proof_10));
|
assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
||||||
Some(BestParaHead {
|
Some(BestParaHead {
|
||||||
@@ -714,7 +735,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ignores_untracked_parachain() {
|
fn ignores_untracked_parachain() {
|
||||||
let (state_root, proof) = prepare_parachain_heads_proof(vec![
|
let (state_root, proof, parachains) = prepare_parachain_heads_proof(vec![
|
||||||
(1, head_data(1, 5)),
|
(1, head_data(1, 5)),
|
||||||
(UNTRACKED_PARACHAIN_ID, head_data(1, 5)),
|
(UNTRACKED_PARACHAIN_ID, head_data(1, 5)),
|
||||||
(2, head_data(1, 5)),
|
(2, head_data(1, 5)),
|
||||||
@@ -726,7 +747,7 @@ mod tests {
|
|||||||
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(0, test_relay_header(0, state_root).hash()),
|
(0, test_relay_header(0, state_root).hash()),
|
||||||
vec![ParaId(1), ParaId(UNTRACKED_PARACHAIN_ID), ParaId(2)],
|
parachains,
|
||||||
proof,
|
proof,
|
||||||
));
|
));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -751,32 +772,35 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn does_nothing_when_already_imported_this_head_at_previous_relay_header() {
|
fn does_nothing_when_already_imported_this_head_at_previous_relay_header() {
|
||||||
let (state_root, proof) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
|
let (state_root, proof, parachains) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// import head#0 of parachain#1 at relay block#0
|
// import head#0 of parachain#1 at relay block#0
|
||||||
initialize(state_root);
|
initialize(state_root);
|
||||||
assert_ok!(import_parachain_1_head(0, state_root, proof.clone()));
|
assert_ok!(import_parachain_1_head(0, state_root, parachains.clone(), proof.clone()));
|
||||||
assert_eq!(BestParaHeads::<TestRuntime>::get(ParaId(1)), Some(initial_best_head(1)));
|
assert_eq!(BestParaHeads::<TestRuntime>::get(ParaId(1)), Some(initial_best_head(1)));
|
||||||
|
|
||||||
// try to import head#0 of parachain#1 at relay block#1
|
// try to import head#0 of parachain#1 at relay block#1
|
||||||
// => call succeeds, but nothing is changed
|
// => call succeeds, but nothing is changed
|
||||||
proceed(1, state_root);
|
proceed(1, state_root);
|
||||||
assert_ok!(import_parachain_1_head(1, state_root, proof));
|
assert_ok!(import_parachain_1_head(1, state_root, parachains, proof));
|
||||||
assert_eq!(BestParaHeads::<TestRuntime>::get(ParaId(1)), Some(initial_best_head(1)));
|
assert_eq!(BestParaHeads::<TestRuntime>::get(ParaId(1)), Some(initial_best_head(1)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn does_nothing_when_already_imported_head_at_better_relay_header() {
|
fn does_nothing_when_already_imported_head_at_better_relay_header() {
|
||||||
let (state_root_5, proof_5) = prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
let (state_root_5, proof_5, parachains_5) =
|
||||||
let (state_root_10, proof_10) = prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
||||||
|
let (state_root_10, proof_10, parachains_10) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// start with relay block #0
|
// start with relay block #0
|
||||||
initialize(state_root_5);
|
initialize(state_root_5);
|
||||||
|
|
||||||
// head#10 of parachain#1 at relay block#1
|
// head#10 of parachain#1 at relay block#1
|
||||||
proceed(1, state_root_10);
|
proceed(1, state_root_10);
|
||||||
assert_ok!(import_parachain_1_head(1, state_root_10, proof_10));
|
assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
||||||
Some(BestParaHead {
|
Some(BestParaHead {
|
||||||
@@ -786,9 +810,9 @@ mod tests {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// now try to import head#1 at relay block#0
|
// now try to import head#5 at relay block#0
|
||||||
// => nothing is changed, because better head has already been imported
|
// => nothing is changed, because better head has already been imported
|
||||||
assert_ok!(import_parachain_1_head(0, state_root_5, proof_5));
|
assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
BestParaHeads::<TestRuntime>::get(ParaId(1)),
|
||||||
Some(BestParaHead {
|
Some(BestParaHead {
|
||||||
@@ -807,7 +831,8 @@ mod tests {
|
|||||||
|
|
||||||
// import exactly `HeadsToKeep` headers
|
// import exactly `HeadsToKeep` headers
|
||||||
for i in 0..heads_to_keep {
|
for i in 0..heads_to_keep {
|
||||||
let (state_root, proof) = prepare_parachain_heads_proof(vec![(1, head_data(1, i))]);
|
let (state_root, proof, parachains) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, i))]);
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
initialize(state_root);
|
initialize(state_root);
|
||||||
} else {
|
} else {
|
||||||
@@ -815,7 +840,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let expected_weight = weight_of_import_parachain_1_head(&proof, false);
|
let expected_weight = weight_of_import_parachain_1_head(&proof, false);
|
||||||
let result = import_parachain_1_head(i, state_root, proof);
|
let result = import_parachain_1_head(i, state_root, parachains, proof);
|
||||||
assert_ok!(result);
|
assert_ok!(result);
|
||||||
assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight));
|
assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight));
|
||||||
}
|
}
|
||||||
@@ -827,11 +852,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// import next relay chain header and next parachain head
|
// import next relay chain header and next parachain head
|
||||||
let (state_root, proof) =
|
let (state_root, proof, parachains) =
|
||||||
prepare_parachain_heads_proof(vec![(1, head_data(1, heads_to_keep))]);
|
prepare_parachain_heads_proof(vec![(1, head_data(1, heads_to_keep))]);
|
||||||
proceed(heads_to_keep, state_root);
|
proceed(heads_to_keep, state_root);
|
||||||
let expected_weight = weight_of_import_parachain_1_head(&proof, true);
|
let expected_weight = weight_of_import_parachain_1_head(&proof, true);
|
||||||
let result = import_parachain_1_head(heads_to_keep, state_root, proof);
|
let result = import_parachain_1_head(heads_to_keep, state_root, parachains, proof);
|
||||||
assert_ok!(result);
|
assert_ok!(result);
|
||||||
assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight));
|
assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight));
|
||||||
|
|
||||||
@@ -848,14 +873,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_on_unknown_relay_chain_block() {
|
fn fails_on_unknown_relay_chain_block() {
|
||||||
let (state_root, proof) = prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
let (state_root, proof, parachains) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// start with relay block #0
|
// start with relay block #0
|
||||||
initialize(state_root);
|
initialize(state_root);
|
||||||
|
|
||||||
// try to import head#5 of parachain#1 at unknown relay chain block #1
|
// try to import head#5 of parachain#1 at unknown relay chain block #1
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
import_parachain_1_head(1, state_root, proof),
|
import_parachain_1_head(1, state_root, parachains, proof),
|
||||||
Error::<TestRuntime>::UnknownRelayChainBlock
|
Error::<TestRuntime>::UnknownRelayChainBlock
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -863,14 +889,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_on_invalid_storage_proof() {
|
fn fails_on_invalid_storage_proof() {
|
||||||
let (_state_root, proof) = prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
let (_state_root, proof, parachains) =
|
||||||
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// start with relay block #0
|
// start with relay block #0
|
||||||
initialize(Default::default());
|
initialize(Default::default());
|
||||||
|
|
||||||
// try to import head#5 of parachain#1 at relay chain block #0
|
// try to import head#5 of parachain#1 at relay chain block #0
|
||||||
assert_noop!(
|
assert_noop!(
|
||||||
import_parachain_1_head(0, Default::default(), proof),
|
import_parachain_1_head(0, Default::default(), parachains, proof),
|
||||||
Error::<TestRuntime>::InvalidStorageProof
|
Error::<TestRuntime>::InvalidStorageProof
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -878,15 +905,16 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_not_rewriting_existing_head_if_failed_to_read_updated_head() {
|
fn is_not_rewriting_existing_head_if_failed_to_read_updated_head() {
|
||||||
let (state_root_5, proof_5) = prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
let (state_root_5, proof_5, parachains_5) =
|
||||||
let (state_root_10_at_20, proof_10_at_20) =
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]);
|
||||||
|
let (state_root_10_at_20, proof_10_at_20, parachains_10_at_20) =
|
||||||
prepare_parachain_heads_proof(vec![(2, head_data(2, 10))]);
|
prepare_parachain_heads_proof(vec![(2, head_data(2, 10))]);
|
||||||
let (state_root_10_at_30, proof_10_at_30) =
|
let (state_root_10_at_30, proof_10_at_30, parachains_10_at_30) =
|
||||||
prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
|
prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]);
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
// we've already imported head#5 of parachain#1 at relay block#10
|
// we've already imported head#5 of parachain#1 at relay block#10
|
||||||
initialize(state_root_5);
|
initialize(state_root_5);
|
||||||
import_parachain_1_head(0, state_root_5, proof_5).expect("ok");
|
import_parachain_1_head(0, state_root_5, parachains_5, proof_5).expect("ok");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Pallet::<TestRuntime>::best_parachain_head(ParaId(1)),
|
Pallet::<TestRuntime>::best_parachain_head(ParaId(1)),
|
||||||
Some(head_data(1, 5))
|
Some(head_data(1, 5))
|
||||||
@@ -900,7 +928,7 @@ mod tests {
|
|||||||
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(20, test_relay_header(20, state_root_10_at_20).hash()),
|
(20, test_relay_header(20, state_root_10_at_20).hash()),
|
||||||
vec![ParaId(1)],
|
parachains_10_at_20,
|
||||||
proof_10_at_20,
|
proof_10_at_20,
|
||||||
),);
|
),);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -916,7 +944,7 @@ mod tests {
|
|||||||
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
assert_ok!(Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
(30, test_relay_header(30, state_root_10_at_30).hash()),
|
(30, test_relay_header(30, state_root_10_at_30).hash()),
|
||||||
vec![ParaId(1)],
|
parachains_10_at_30,
|
||||||
proof_10_at_30,
|
proof_10_at_30,
|
||||||
),);
|
),);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
//! parachain finality proofs synchronization pipelines.
|
//! parachain finality proofs synchronization pipelines.
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId};
|
use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId};
|
||||||
use pallet_bridge_parachains::{
|
use pallet_bridge_parachains::{
|
||||||
Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash,
|
Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash,
|
||||||
RelayBlockHasher, RelayBlockNumber,
|
RelayBlockHasher, RelayBlockNumber,
|
||||||
@@ -71,7 +71,7 @@ pub trait SubmitParachainHeadsCallBuilder<P: SubstrateParachainsPipeline>:
|
|||||||
/// function of bridge parachains module at the target chain.
|
/// function of bridge parachains module at the target chain.
|
||||||
fn build_submit_parachain_heads_call(
|
fn build_submit_parachain_heads_call(
|
||||||
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
||||||
parachains: Vec<ParaId>,
|
parachains: Vec<(ParaId, ParaHash)>,
|
||||||
parachain_heads_proof: ParaHeadsProof,
|
parachain_heads_proof: ParaHeadsProof,
|
||||||
) -> CallOf<P::TargetChain>;
|
) -> CallOf<P::TargetChain>;
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ where
|
|||||||
{
|
{
|
||||||
fn build_submit_parachain_heads_call(
|
fn build_submit_parachain_heads_call(
|
||||||
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
||||||
parachains: Vec<ParaId>,
|
parachains: Vec<(ParaId, ParaHash)>,
|
||||||
parachain_heads_proof: ParaHeadsProof,
|
parachain_heads_proof: ParaHeadsProof,
|
||||||
) -> CallOf<P::TargetChain> {
|
) -> CallOf<P::TargetChain> {
|
||||||
BridgeParachainsCall::<R, I>::submit_parachain_heads {
|
BridgeParachainsCall::<R, I>::submit_parachain_heads {
|
||||||
|
|||||||
@@ -160,23 +160,46 @@ where
|
|||||||
&self,
|
&self,
|
||||||
at_block: HeaderIdOf<P::SourceRelayChain>,
|
at_block: HeaderIdOf<P::SourceRelayChain>,
|
||||||
parachains: &[ParaId],
|
parachains: &[ParaId],
|
||||||
) -> Result<ParaHeadsProof, Self::Error> {
|
) -> Result<(ParaHeadsProof, Vec<ParaHash>), Self::Error> {
|
||||||
let storage_keys = parachains
|
if parachains.len() != 1 || parachains[0].0 != P::SOURCE_PARACHAIN_PARA_ID {
|
||||||
.iter()
|
return Err(SubstrateError::Custom(format!(
|
||||||
.map(|para_id| {
|
"Trying to prove unexpected parachains {:?}. Expected {:?}",
|
||||||
parachain_head_storage_key_at_source(
|
parachains,
|
||||||
P::SourceRelayChain::PARAS_PALLET_NAME,
|
P::SOURCE_PARACHAIN_PARA_ID,
|
||||||
*para_id,
|
)))
|
||||||
)
|
}
|
||||||
})
|
|
||||||
.collect();
|
let parachain = parachains[0];
|
||||||
|
let storage_key =
|
||||||
|
parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, parachain);
|
||||||
let parachain_heads_proof = self
|
let parachain_heads_proof = self
|
||||||
.client
|
.client
|
||||||
.prove_storage(storage_keys, at_block.1)
|
.prove_storage(vec![storage_key.clone()], at_block.1)
|
||||||
.await?
|
.await?
|
||||||
.iter_nodes()
|
.iter_nodes()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(ParaHeadsProof(parachain_heads_proof))
|
// why we're reading parachain head here once again (it has already been read at the
|
||||||
|
// `parachain_head`)? that's because `parachain_head` sometimes returns obsolete parachain
|
||||||
|
// head and loop sometimes asks to prove this obsolete head and gets other (actual) head
|
||||||
|
// instead
|
||||||
|
//
|
||||||
|
// => since we want to provide proper hashes in our `submit_parachain_heads` call, we're
|
||||||
|
// rereading actual value here
|
||||||
|
let parachain_head = self
|
||||||
|
.client
|
||||||
|
.raw_storage_value(storage_key, Some(at_block.1))
|
||||||
|
.await?
|
||||||
|
.map(|h| ParaHead::decode(&mut &h.0[..]))
|
||||||
|
.transpose()?
|
||||||
|
.ok_or_else(|| {
|
||||||
|
SubstrateError::Custom(format!(
|
||||||
|
"Failed to read expected parachain {:?} head at {:?}",
|
||||||
|
parachain, at_block
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
let parachain_head_hash = parachain_head.hash();
|
||||||
|
|
||||||
|
Ok((ParaHeadsProof(parachain_heads_proof), vec![parachain_head_hash]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use bp_parachains::{
|
|||||||
best_parachain_head_hash_storage_key_at_target, imported_parachain_head_storage_key_at_target,
|
best_parachain_head_hash_storage_key_at_target, imported_parachain_head_storage_key_at_target,
|
||||||
BestParaHeadHash,
|
BestParaHeadHash,
|
||||||
};
|
};
|
||||||
use bp_polkadot_core::parachains::{ParaHead, ParaHeadsProof, ParaId};
|
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use parachains_relay::{
|
use parachains_relay::{
|
||||||
parachains_loop::TargetClient, parachains_loop_metrics::ParachainsLoopMetrics,
|
parachains_loop::TargetClient, parachains_loop_metrics::ParachainsLoopMetrics,
|
||||||
@@ -166,7 +166,7 @@ where
|
|||||||
async fn submit_parachain_heads_proof(
|
async fn submit_parachain_heads_proof(
|
||||||
&self,
|
&self,
|
||||||
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
at_relay_block: HeaderIdOf<P::SourceRelayChain>,
|
||||||
updated_parachains: Vec<ParaId>,
|
updated_parachains: Vec<(ParaId, ParaHash)>,
|
||||||
proof: ParaHeadsProof,
|
proof: ParaHeadsProof,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
let genesis_hash = *self.client.genesis_hash();
|
let genesis_hash = *self.client.genesis_hash();
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ pub enum ParaHashAtSource {
|
|||||||
Unavailable,
|
Unavailable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ParaHashAtSource {
|
||||||
|
/// Return parachain head hash, if available.
|
||||||
|
pub fn hash(&self) -> Option<&ParaHash> {
|
||||||
|
match *self {
|
||||||
|
ParaHashAtSource::Some(ref para_hash) => Some(para_hash),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Source client used in parachain heads synchronization loop.
|
/// Source client used in parachain heads synchronization loop.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait SourceClient<P: ParachainsPipeline>: RelayClient {
|
pub trait SourceClient<P: ParachainsPipeline>: RelayClient {
|
||||||
@@ -87,11 +97,15 @@ pub trait SourceClient<P: ParachainsPipeline>: RelayClient {
|
|||||||
) -> Result<ParaHashAtSource, Self::Error>;
|
) -> Result<ParaHashAtSource, Self::Error>;
|
||||||
|
|
||||||
/// Get parachain heads proof.
|
/// Get parachain heads proof.
|
||||||
|
///
|
||||||
|
/// The number and order of entries in the resulting parachain head hashes vector must match the
|
||||||
|
/// number and order of parachains in the `parachains` vector. The incorrect implementation will
|
||||||
|
/// result in panic.
|
||||||
async fn prove_parachain_heads(
|
async fn prove_parachain_heads(
|
||||||
&self,
|
&self,
|
||||||
at_block: HeaderIdOf<P::SourceChain>,
|
at_block: HeaderIdOf<P::SourceChain>,
|
||||||
parachains: &[ParaId],
|
parachains: &[ParaId],
|
||||||
) -> Result<ParaHeadsProof, Self::Error>;
|
) -> Result<(ParaHeadsProof, Vec<ParaHash>), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Target client used in parachain heads synchronization loop.
|
/// Target client used in parachain heads synchronization loop.
|
||||||
@@ -121,7 +135,7 @@ pub trait TargetClient<P: ParachainsPipeline>: RelayClient {
|
|||||||
async fn submit_parachain_heads_proof(
|
async fn submit_parachain_heads_proof(
|
||||||
&self,
|
&self,
|
||||||
at_source_block: HeaderIdOf<P::SourceChain>,
|
at_source_block: HeaderIdOf<P::SourceChain>,
|
||||||
updated_parachains: Vec<ParaId>,
|
updated_parachains: Vec<(ParaId, ParaHash)>,
|
||||||
proof: ParaHeadsProof,
|
proof: ParaHeadsProof,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
@@ -274,7 +288,7 @@ where
|
|||||||
);
|
);
|
||||||
|
|
||||||
if is_update_required {
|
if is_update_required {
|
||||||
let heads_proofs = source_client
|
let (heads_proofs, head_hashes) = source_client
|
||||||
.prove_parachain_heads(best_finalized_relay_block, &updated_ids)
|
.prove_parachain_heads(best_finalized_relay_block, &updated_ids)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@@ -292,10 +306,17 @@ where
|
|||||||
P::SourceChain::NAME,
|
P::SourceChain::NAME,
|
||||||
P::TargetChain::NAME,
|
P::TargetChain::NAME,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
head_hashes.len(),
|
||||||
|
updated_ids.len(),
|
||||||
|
"Incorrect parachains SourceClient implementation"
|
||||||
|
);
|
||||||
|
|
||||||
target_client
|
target_client
|
||||||
.submit_parachain_heads_proof(
|
.submit_parachain_heads_proof(
|
||||||
best_finalized_relay_block,
|
best_finalized_relay_block,
|
||||||
updated_ids.clone(),
|
updated_ids.iter().cloned().zip(head_hashes).collect(),
|
||||||
heads_proofs,
|
heads_proofs,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -394,7 +415,7 @@ where
|
|||||||
|
|
||||||
needs_update
|
needs_update
|
||||||
})
|
})
|
||||||
.map(|((para_id, _), _)| para_id)
|
.map(|((para, _), _)| para)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -666,7 +687,7 @@ mod tests {
|
|||||||
&self,
|
&self,
|
||||||
_at_block: HeaderIdOf<TestChain>,
|
_at_block: HeaderIdOf<TestChain>,
|
||||||
parachains: &[ParaId],
|
parachains: &[ParaId],
|
||||||
) -> Result<ParaHeadsProof, TestError> {
|
) -> Result<(ParaHeadsProof, Vec<ParaHash>), TestError> {
|
||||||
let mut proofs = Vec::new();
|
let mut proofs = Vec::new();
|
||||||
for para_id in parachains {
|
for para_id in parachains {
|
||||||
proofs.push(
|
proofs.push(
|
||||||
@@ -680,7 +701,7 @@ mod tests {
|
|||||||
.ok_or(TestError::MissingParachainHeadProof)?,
|
.ok_or(TestError::MissingParachainHeadProof)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(ParaHeadsProof(proofs))
|
Ok((ParaHeadsProof(proofs), vec![Default::default(); parachains.len()]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,7 +730,7 @@ mod tests {
|
|||||||
async fn submit_parachain_heads_proof(
|
async fn submit_parachain_heads_proof(
|
||||||
&self,
|
&self,
|
||||||
_at_source_block: HeaderIdOf<TestChain>,
|
_at_source_block: HeaderIdOf<TestChain>,
|
||||||
_updated_parachains: Vec<ParaId>,
|
_updated_parachains: Vec<(ParaId, ParaHash)>,
|
||||||
_proof: ParaHeadsProof,
|
_proof: ParaHeadsProof,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.data.lock().await.target_submit_result.clone()?;
|
self.data.lock().await.target_submit_result.clone()?;
|
||||||
|
|||||||
Reference in New Issue
Block a user