diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs index 5aa7f1c095d54..aab3280a3493f 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs @@ -1146,7 +1146,7 @@ pub(crate) mod tests { relayer_id_at_bridged_chain: relayer_account_at_bridged_chain(), proof: FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), - storage_proof: vec![], + storage: Default::default(), lane: TestLaneId::get(), nonces_start: pallet_bridge_messages::InboundLanes::::get( TEST_LANE_ID, diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs index 0fe9935dbdb6d..b86ab45fdeeaf 100644 --- a/bridges/bin/runtime-common/src/messages.rs +++ b/bridges/bin/runtime-common/src/messages.rs @@ -20,8 +20,6 @@ //! pallet is used to dispatch incoming messages. Message identified by a tuple //! of to elements - message lane id and message nonce. -pub use bp_runtime::{RangeInclusiveExt, UnderlyingChainOf, UnderlyingChainProvider}; - use bp_header_chain::HeaderChain; use bp_messages::{ source_chain::TargetHeaderChain, @@ -29,10 +27,12 @@ use bp_messages::{ InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, VerificationError, }; -use bp_runtime::{Chain, RawStorageProof, Size, StorageProofChecker}; +pub use bp_runtime::{ + Chain, RangeInclusiveExt, RawStorageProof, Size, TrustedVecDb, UnderlyingChainOf, + UnderlyingChainProvider, UntrustedVecDb, +}; use codec::{Decode, Encode}; use frame_support::{traits::Get, weights::Weight}; -use hash_db::Hasher; use scale_info::TypeInfo; use sp_runtime::RuntimeDebug; use sp_std::{marker::PhantomData, vec::Vec}; @@ -226,8 +226,8 @@ pub mod target { pub struct FromBridgedChainMessagesProof { /// Hash of the finalized bridged header the proof is for. pub bridged_header_hash: BridgedHeaderHash, - /// A storage trie proof of messages being delivered. - pub storage_proof: RawStorageProof, + /// The proved storage containing the messages being delivered. + pub storage: UntrustedVecDb, /// Messages in this proof are sent over this lane. pub lane: LaneId, /// Nonce of the first message being delivered. @@ -238,12 +238,7 @@ pub mod target { impl Size for FromBridgedChainMessagesProof { fn size(&self) -> u32 { - u32::try_from( - self.storage_proof - .iter() - .fold(0usize, |sum, node| sum.saturating_add(node.len())), - ) - .unwrap_or(u32::MAX) + self.storage.size() } } @@ -285,15 +280,14 @@ pub mod target { ) -> Result, VerificationError> { let FromBridgedChainMessagesProof { bridged_header_hash, - storage_proof, + storage, lane, nonces_start, nonces_end, } = proof; - let storage = - B::BridgedHeaderChain::storage_proof_checker(bridged_header_hash, storage_proof) - .map_err(VerificationError::HeaderChain)?; - let mut parser = StorageProofCheckerAdapter::<_, B> { storage, _dummy: Default::default() }; + let storage = B::BridgedHeaderChain::verify_vec_db_storage(bridged_header_hash, storage) + .map_err(VerificationError::HeaderChain)?; + let mut parser = StorageAdapter:: { storage, _dummy: Default::default() }; let nonces_range = nonces_start..=nonces_end; // receiving proofs where end < begin is ok (if proof includes outbound lane state) @@ -325,11 +319,8 @@ pub mod target { return Err(VerificationError::EmptyMessageProof) } - // check that the storage proof doesn't have any untouched trie nodes - parser - .storage - .ensure_no_unused_nodes() - .map_err(VerificationError::StorageProof)?; + // Check that the `VecDb` doesn't have any untouched keys. + parser.storage.ensure_no_unused_keys().map_err(VerificationError::VecDb)?; // We only support single lane messages in this generated_schema let mut proved_messages = ProvedMessages::new(); @@ -338,12 +329,12 @@ pub mod target { Ok(proved_messages) } - struct StorageProofCheckerAdapter { - storage: StorageProofChecker, + struct StorageAdapter { + storage: TrustedVecDb, _dummy: sp_std::marker::PhantomData, } - impl StorageProofCheckerAdapter { + impl StorageAdapter { fn read_and_decode_outbound_lane_data( &mut self, lane_id: &LaneId, @@ -354,7 +345,7 @@ pub mod target { ); self.storage - .read_and_decode_opt_value(storage_outbound_lane_data_key.0.as_ref()) + .get_and_decode_optional(&storage_outbound_lane_data_key) .map_err(VerificationError::OutboundLaneStorage) } @@ -368,7 +359,7 @@ pub mod target { message_key.nonce, ); self.storage - .read_and_decode_mandatory_value(storage_message_key.0.as_ref()) + .get_and_decode_mandatory(&storage_message_key) .map_err(VerificationError::MessageStorage) } } @@ -391,7 +382,7 @@ mod tests { mock::*, }; use bp_header_chain::{HeaderChainError, StoredHeaderDataBuilder}; - use bp_runtime::{HeaderId, StorageProofError}; + use bp_runtime::{HeaderId, VecDbError}; use codec::Encode; use sp_core::H256; use sp_runtime::traits::Header as _; @@ -433,9 +424,11 @@ mod tests { outbound_lane_data: Option, encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, + add_duplicate_key: bool, + add_unused_key: bool, test: impl Fn(target::FromBridgedChainMessagesProof) -> R, ) -> R { - let (state_root, storage_proof) = prepare_messages_storage_proof::( + let (state_root, storage) = prepare_messages_storage_proof::( TEST_LANE_ID, 1..=nonces_end, outbound_lane_data, @@ -443,6 +436,8 @@ mod tests { vec![42], encode_message, encode_outbound_lane_data, + add_duplicate_key, + add_unused_key, ); sp_io::TestExternalities::new(Default::default()).execute_with(move || { @@ -465,7 +460,7 @@ mod tests { ); test(target::FromBridgedChainMessagesProof { bridged_header_hash, - storage_proof, + storage, lane: TEST_LANE_ID, nonces_start: 1, nonces_end, @@ -476,9 +471,15 @@ mod tests { #[test] fn messages_proof_is_rejected_if_declared_less_than_actual_number_of_messages() { assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - target::verify_messages_proof::(proof, 5) - }), + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { target::verify_messages_proof::(proof, 5) } + ), Err(VerificationError::MessagesCountMismatch), ); } @@ -486,9 +487,15 @@ mod tests { #[test] fn messages_proof_is_rejected_if_declared_more_than_actual_number_of_messages() { assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - target::verify_messages_proof::(proof, 15) - }), + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { target::verify_messages_proof::(proof, 15) } + ), Err(VerificationError::MessagesCountMismatch), ); } @@ -496,12 +503,22 @@ mod tests { #[test] fn message_proof_is_rejected_if_header_is_missing_from_the_chain() { assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - let bridged_header_hash = - pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; - pallet_bridge_grandpa::ImportedHeaders::::remove(bridged_header_hash); - target::verify_messages_proof::(proof, 10) - }), + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { + let bridged_header_hash = + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; + pallet_bridge_grandpa::ImportedHeaders::::remove( + bridged_header_hash, + ); + target::verify_messages_proof::(proof, 10) + } + ), Err(VerificationError::HeaderChain(HeaderChainError::UnknownHeader)), ); } @@ -509,51 +526,63 @@ mod tests { #[test] fn message_proof_is_rejected_if_header_state_root_mismatches() { assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { - let bridged_header_hash = - pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; - pallet_bridge_grandpa::ImportedHeaders::::insert( - bridged_header_hash, - BridgedChainHeader::new( - 0, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - ) - .build(), - ); - target::verify_messages_proof::(proof, 10) - }), - Err(VerificationError::HeaderChain(HeaderChainError::StorageProof( - StorageProofError::StorageRootMismatch - ))), + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { + let bridged_header_hash = + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + BridgedChainHeader::new( + 0, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ) + .build(), + ); + target::verify_messages_proof::(proof, 10) + } + ), + Err(VerificationError::HeaderChain(HeaderChainError::VecDb(VecDbError::InvalidProof))), ); } #[test] fn message_proof_is_rejected_if_it_has_duplicate_trie_nodes() { assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |mut proof| { - let node = proof.storage_proof.pop().unwrap(); - proof.storage_proof.push(node.clone()); - proof.storage_proof.push(node); - target::verify_messages_proof::(proof, 10) - },), - Err(VerificationError::HeaderChain(HeaderChainError::StorageProof( - StorageProofError::DuplicateNodesInProof - ))), + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + true, + false, + |proof| { target::verify_messages_proof::(proof, 10) }, + ), + Err(VerificationError::HeaderChain(HeaderChainError::VecDb(VecDbError::InvalidProof))), ); } #[test] fn message_proof_is_rejected_if_it_has_unused_trie_nodes() { assert_eq!( - using_messages_proof(10, None, encode_all_messages, encode_lane_data, |mut proof| { - proof.storage_proof.push(vec![42]); - target::verify_messages_proof::(proof, 10) - },), - Err(VerificationError::StorageProof(StorageProofError::UnusedNodesInTheProof)), + using_messages_proof( + 10, + None, + encode_all_messages, + encode_lane_data, + false, + true, + |proof| { target::verify_messages_proof::(proof, 10) }, + ), + Err(VerificationError::VecDb(VecDbError::UnusedKey)), ); } @@ -565,9 +594,11 @@ mod tests { None, |n, m| if n != 5 { Some(m.encode()) } else { None }, encode_lane_data, + false, + false, |proof| target::verify_messages_proof::(proof, 10) ), - Err(VerificationError::MessageStorage(StorageProofError::StorageValueEmpty)), + Err(VerificationError::MessageStorage(VecDbError::EmptyVal)), ); } @@ -585,9 +616,11 @@ mod tests { Some(m) }, encode_lane_data, + false, + false, |proof| target::verify_messages_proof::(proof, 10), ), - Err(VerificationError::MessageStorage(StorageProofError::StorageValueDecodeFailed(_))), + Err(VerificationError::MessageStorage(VecDbError::DecodeError)), ); } @@ -607,20 +640,26 @@ mod tests { d.truncate(1); d }, + false, + false, |proof| target::verify_messages_proof::(proof, 10), ), - Err(VerificationError::OutboundLaneStorage( - StorageProofError::StorageValueDecodeFailed(_) - )), + Err(VerificationError::OutboundLaneStorage(VecDbError::DecodeError)), ); } #[test] fn message_proof_is_rejected_if_it_is_empty() { assert_eq!( - using_messages_proof(0, None, encode_all_messages, encode_lane_data, |proof| { - target::verify_messages_proof::(proof, 0) - },), + using_messages_proof( + 0, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |proof| { target::verify_messages_proof::(proof, 0) }, + ), Err(VerificationError::EmptyMessageProof), ); } @@ -637,6 +676,8 @@ mod tests { }), encode_all_messages, encode_lane_data, + false, + false, |proof| target::verify_messages_proof::(proof, 0), ), Ok(vec![( @@ -667,6 +708,8 @@ mod tests { }), encode_all_messages, encode_lane_data, + false, + false, |proof| target::verify_messages_proof::(proof, 1), ), Ok(vec![( @@ -691,10 +734,18 @@ mod tests { #[test] fn verify_messages_proof_does_not_panic_if_messages_count_mismatches() { assert_eq!( - using_messages_proof(1, None, encode_all_messages, encode_lane_data, |mut proof| { - proof.nonces_end = u64::MAX; - target::verify_messages_proof::(proof, u32::MAX) - },), + using_messages_proof( + 1, + None, + encode_all_messages, + encode_lane_data, + false, + false, + |mut proof| { + proof.nonces_end = u64::MAX; + target::verify_messages_proof::(proof, u32::MAX) + }, + ), Err(VerificationError::MessagesCountMismatch), ); } diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs index 74494f7908045..5d92e9e68711e 100644 --- a/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -85,7 +85,7 @@ where B: MessageBridge, { // prepare storage proof - let (state_root, storage_proof) = prepare_messages_storage_proof::( + let (state_root, storage) = prepare_messages_storage_proof::( params.lane, params.message_nonces.clone(), params.outbound_lane_data.clone(), @@ -93,6 +93,8 @@ where prepare_inbound_message(¶ms, message_generator), encode_all_messages, encode_lane_data, + false, + false, ); // update runtime storage @@ -101,7 +103,7 @@ where ( FromBridgedChainMessagesProof { bridged_header_hash, - storage_proof, + storage, lane: params.lane, nonces_start: *params.message_nonces.start(), nonces_end: *params.message_nonces.end(), @@ -129,7 +131,7 @@ where UnderlyingChainOf>: Chain + Parachain, { // prepare storage proof - let (state_root, storage_proof) = prepare_messages_storage_proof::( + let (state_root, storage) = prepare_messages_storage_proof::( params.lane, params.message_nonces.clone(), params.outbound_lane_data.clone(), @@ -137,6 +139,8 @@ where prepare_inbound_message(¶ms, message_generator), encode_all_messages, encode_lane_data, + false, + false, ); // update runtime storage @@ -146,7 +150,7 @@ where ( FromBridgedChainMessagesProof { bridged_header_hash, - storage_proof, + storage, lane: params.lane, nonces_start: *params.message_nonces.start(), nonces_end: *params.message_nonces.end(), diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/bin/runtime-common/src/messages_call_ext.rs index fb07f7b6dd691..a29e9b80a50d0 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/bin/runtime-common/src/messages_call_ext.rs @@ -420,7 +420,7 @@ mod tests { dispatch_weight: frame_support::weights::Weight::zero(), proof: FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), - storage_proof: vec![], + storage: Default::default(), lane: LaneId([0, 0, 0, 0]), nonces_start, nonces_end, diff --git a/bridges/bin/runtime-common/src/messages_generation.rs b/bridges/bin/runtime-common/src/messages_generation.rs index c37aaa5d4d537..be7c0458d09a5 100644 --- a/bridges/bin/runtime-common/src/messages_generation.rs +++ b/bridges/bin/runtime-common/src/messages_generation.rs @@ -22,10 +22,17 @@ use bp_messages::{ storage_keys, InboundLaneData, LaneId, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, }; -use bp_runtime::{record_all_trie_keys, RawStorageProof, StorageProofSize}; +use bp_runtime::{ + record_all_trie_keys, Chain, RawStorageProof, StorageProofSize, UnderlyingChainOf, + UntrustedVecDb, +}; use codec::Encode; +use frame_support::sp_runtime::StateVersion; use sp_std::{ops::RangeInclusive, prelude::*}; -use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; +use sp_trie::{ + trie_types::TrieDBMutBuilderV1, LayoutV0, LayoutV1, MemoryDB, StorageProof, TrieConfiguration, + TrieDBMutBuilder, TrieMut, +}; /// Simple and correct message data encode function. pub fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option> { @@ -40,6 +47,7 @@ pub fn encode_lane_data(d: &OutboundLaneData) -> Vec { /// Prepare storage proof of given messages. /// /// Returns state trie root and nodes with prepared messages. +#[allow(clippy::too_many_arguments)] pub fn prepare_messages_storage_proof( lane: LaneId, message_nonces: RangeInclusive, @@ -48,10 +56,60 @@ pub fn prepare_messages_storage_proof( message_payload: MessagePayload, encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, -) -> (HashOf>, RawStorageProof) + add_duplicate_key: bool, + add_unused_key: bool, +) -> (HashOf>, UntrustedVecDb) where B: MessageBridge, HashOf>: Copy + Default, +{ + match >>::STATE_VERSION { + StateVersion::V0 => + do_prepare_messages_storage_proof::>>>( + lane, + message_nonces, + outbound_lane_data, + size, + message_payload, + encode_message, + encode_outbound_lane_data, + add_duplicate_key, + add_unused_key, + ), + StateVersion::V1 => + do_prepare_messages_storage_proof::>>>( + lane, + message_nonces, + outbound_lane_data, + size, + message_payload, + encode_message, + encode_outbound_lane_data, + add_duplicate_key, + add_unused_key, + ), + } +} + +/// Prepare storage proof of given messages. +/// +/// Returns state trie root and nodes with prepared messages. +#[allow(clippy::too_many_arguments)] +pub fn do_prepare_messages_storage_proof( + lane: LaneId, + message_nonces: RangeInclusive, + outbound_lane_data: Option, + size: StorageProofSize, + message_payload: MessagePayload, + encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, + encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, + add_duplicate_key: bool, + add_unused_key: bool, +) -> (HashOf>, UntrustedVecDb) +where + B: MessageBridge, + L: TrieConfiguration>>, + HashOf>: Copy + Default, { // prepare Bridged chain storage with messages and (optionally) outbound lane state let message_count = message_nonces.end().saturating_sub(*message_nonces.start()) + 1; @@ -59,8 +117,7 @@ where let mut root = Default::default(); let mut mdb = MemoryDB::default(); { - let mut trie = - TrieDBMutBuilderV1::>>::new(&mut mdb, &mut root).build(); + let mut trie = TrieDBMutBuilder::::new(&mut mdb, &mut root).build(); // insert messages for (i, nonce) in message_nonces.into_iter().enumerate() { @@ -96,13 +153,32 @@ where .expect("TrieMut::insert should not fail in benchmarks"); storage_keys.push(storage_key); } + + if add_duplicate_key { + let duplicate_key = storage_keys.last().unwrap().clone(); + storage_keys.push(duplicate_key); + } + + if add_unused_key { + let storage_key = b"unused_key".to_vec(); + trie.insert(&storage_key, b"unused_value") + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + } } // generate storage proof to be delivered to This chain - let storage_proof = record_all_trie_keys::>>, _>(&mdb, &root) + let read_proof = record_all_trie_keys::(&mdb, &root) .map_err(|_| "record_all_trie_keys has failed") .expect("record_all_trie_keys should not fail in benchmarks"); - (root, storage_proof) + let storage = UntrustedVecDb::try_new::>>( + StorageProof::new(read_proof), + root, + storage_keys, + ) + .unwrap(); + (root, storage) } /// Prepare storage proof of given messages delivery. diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index f494746678960..f287aea8de6b7 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -46,7 +46,7 @@ use pallet_transaction_payment::Multiplier; use sp_runtime::{ testing::H256, traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8}, - FixedPointNumber, Perquintill, + FixedPointNumber, Perquintill, StateVersion, }; /// Account identifier at `ThisChain`. @@ -326,6 +326,8 @@ impl Chain for ThisUnderlyingChain { type Nonce = u32; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } @@ -368,6 +370,8 @@ impl Chain for BridgedUnderlyingChain { type Nonce = u32; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } @@ -396,6 +400,8 @@ impl Chain for BridgedUnderlyingParachain { type Nonce = u32; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE } diff --git a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs index ef3ef4ab7b7a9..c990e8a12f367 100644 --- a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs @@ -29,7 +29,7 @@ use frame_support::{ dispatch::DispatchClass, sp_runtime::{MultiAddress, MultiSigner}, }; -use sp_runtime::RuntimeDebug; +use sp_runtime::{RuntimeDebug, StateVersion}; /// BridgeHubKusama parachain. #[derive(RuntimeDebug)] @@ -48,6 +48,8 @@ impl Chain for BridgeHubKusama { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs index 9db71af928e5d..7379b8863b1de 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs @@ -26,7 +26,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; use frame_support::dispatch::DispatchClass; -use sp_runtime::RuntimeDebug; +use sp_runtime::{RuntimeDebug, StateVersion}; /// BridgeHubPolkadot parachain. #[derive(RuntimeDebug)] @@ -45,6 +45,8 @@ impl Chain for BridgeHubPolkadot { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index d7097f01c5316..b37a61f7de5c5 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -25,8 +25,10 @@ use bp_messages::*; use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; -use frame_support::dispatch::DispatchClass; -use sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug}; +use frame_support::{ + dispatch::DispatchClass, + sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug, StateVersion}, +}; /// BridgeHubRococo parachain. #[derive(RuntimeDebug)] @@ -45,6 +47,8 @@ impl Chain for BridgeHubRococo { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 800f290d7bfa4..17ff2c858a1d3 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; use frame_support::dispatch::DispatchClass; -use sp_runtime::RuntimeDebug; +use sp_runtime::{RuntimeDebug, StateVersion}; /// BridgeHubWestend parachain. #[derive(RuntimeDebug)] @@ -44,6 +44,8 @@ impl Chain for BridgeHubWestend { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs index fd7172c5869d4..dcd0b23abbbef 100644 --- a/bridges/chains/chain-kusama/src/lib.rs +++ b/bridges/chains/chain-kusama/src/lib.rs @@ -23,7 +23,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, ChainId}; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Kusama Chain pub struct Kusama; @@ -41,6 +41,8 @@ impl Chain for Kusama { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V0; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/chains/chain-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index f3d300567f2b4..88980a9575016 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -37,7 +37,9 @@ use frame_support::{ }; use frame_system::limits; use scale_info::TypeInfo; -use sp_runtime::{traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill}; +use sp_runtime::{ + traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill, StateVersion, +}; // This chain reuses most of Polkadot primitives. pub use bp_polkadot_core::{ @@ -192,6 +194,8 @@ impl Chain for PolkadotBulletin { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { *BlockLength::get().max.get(DispatchClass::Normal) } diff --git a/bridges/chains/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs index a8cac0467d574..f4b262d40735d 100644 --- a/bridges/chains/chain-polkadot/src/lib.rs +++ b/bridges/chains/chain-polkadot/src/lib.rs @@ -25,7 +25,7 @@ use bp_header_chain::ChainWithGrandpa; use bp_runtime::{ decl_bridge_finality_runtime_apis, extensions::PrevalidateAttests, Chain, ChainId, }; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Polkadot Chain pub struct Polkadot; @@ -43,6 +43,8 @@ impl Chain for Polkadot { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V0; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/chains/chain-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs index b290fe71c829d..bfcafdf41ea2e 100644 --- a/bridges/chains/chain-rococo/src/lib.rs +++ b/bridges/chains/chain-rococo/src/lib.rs @@ -23,7 +23,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, ChainId}; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Rococo Chain pub struct Rococo; @@ -41,6 +41,8 @@ impl Chain for Rococo { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/chains/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs index ef451f7de0a96..2a247e03e59d6 100644 --- a/bridges/chains/chain-westend/src/lib.rs +++ b/bridges/chains/chain-westend/src/lib.rs @@ -23,7 +23,7 @@ pub use bp_polkadot_core::*; use bp_header_chain::ChainWithGrandpa; use bp_runtime::{decl_bridge_finality_runtime_apis, Chain, ChainId}; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; /// Westend Chain pub struct Westend; @@ -41,6 +41,8 @@ impl Chain for Westend { type Nonce = Nonce; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { max_extrinsic_size() } diff --git a/bridges/modules/beefy/src/mock.rs b/bridges/modules/beefy/src/mock.rs index c99566b6b06d1..173a48dba62ce 100644 --- a/bridges/modules/beefy/src/mock.rs +++ b/bridges/modules/beefy/src/mock.rs @@ -29,6 +29,7 @@ use sp_core::{sr25519::Signature, Pair}; use sp_runtime::{ testing::{Header, H256}, traits::{BlakeTwo256, Hash}, + StateVersion, }; pub use sp_consensus_beefy::ecdsa_crypto::{AuthorityId as BeefyId, Pair as BeefyPair}; @@ -93,6 +94,8 @@ impl Chain for TestBridgedChain { type Nonce = u64; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/modules/grandpa/src/mock.rs b/bridges/modules/grandpa/src/mock.rs index 27df9d9c78f54..71af6182e057c 100644 --- a/bridges/modules/grandpa/src/mock.rs +++ b/bridges/modules/grandpa/src/mock.rs @@ -20,7 +20,8 @@ use bp_header_chain::ChainWithGrandpa; use bp_runtime::{Chain, ChainId}; use frame_support::{ - construct_runtime, derive_impl, parameter_types, traits::Hooks, weights::Weight, + construct_runtime, derive_impl, parameter_types, sp_runtime::StateVersion, traits::Hooks, + weights::Weight, }; use sp_core::sr25519::Signature; @@ -78,6 +79,8 @@ impl Chain for TestBridgedChain { type Nonce = u64; type Signature = Signature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/modules/messages/src/weights.rs b/bridges/modules/messages/src/weights.rs index 5bf7d56756079..51152b83d9bca 100644 --- a/bridges/modules/messages/src/weights.rs +++ b/bridges/modules/messages/src/weights.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for pallet_bridge_messages //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! HOSTNAME: `serban-ROG-Zephyrus`, CPU: `12th Gen Intel(R) Core(TM) i7-12700H` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -82,10 +82,10 @@ impl WeightInfo for BridgeWeight { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_321 nanoseconds. - Weight::from_parts(54_478_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 34_049 nanoseconds. + Weight::from_parts(39_460_000, 52645) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -105,10 +105,10 @@ impl WeightInfo for BridgeWeight { /// 51655, mode: MaxEncodedLen) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_597 nanoseconds. - Weight::from_parts(69_267_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 44_030 nanoseconds. + Weight::from_parts(48_036_000, 52645) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -128,10 +128,10 @@ impl WeightInfo for BridgeWeight { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_079 nanoseconds. - Weight::from_parts(65_905_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 42_839 nanoseconds. + Weight::from_parts(45_052_000, 52645) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -151,10 +151,10 @@ impl WeightInfo for BridgeWeight { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 50_588 nanoseconds. - Weight::from_parts(53_544_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 33_925 nanoseconds. + Weight::from_parts(36_321_000, 52645) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -174,10 +174,10 @@ impl WeightInfo for BridgeWeight { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 78_269 nanoseconds. - Weight::from_parts(81_748_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 50_591 nanoseconds. + Weight::from_parts(56_245_000, 52645) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -202,10 +202,10 @@ impl WeightInfo for BridgeWeight { /// mode: MaxEncodedLen) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `579` - // Estimated: `9584` - // Minimum execution time: 45_786 nanoseconds. - Weight::from_parts(47_382_000, 9584) + // Measured: `453` + // Estimated: `3530` + // Minimum execution time: 33_199 nanoseconds. + Weight::from_parts(34_349_000, 3530) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -230,10 +230,10 @@ impl WeightInfo for BridgeWeight { /// mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `9584` - // Minimum execution time: 44_544 nanoseconds. - Weight::from_parts(45_451_000, 9584) + // Measured: `470` + // Estimated: `3530` + // Minimum execution time: 32_221 nanoseconds. + Weight::from_parts(33_944_000, 3530) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -258,10 +258,10 @@ impl WeightInfo for BridgeWeight { /// mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `12124` - // Minimum execution time: 47_344 nanoseconds. - Weight::from_parts(48_311_000, 12124) + // Measured: `470` + // Estimated: `6070` + // Minimum execution time: 34_880 nanoseconds. + Weight::from_parts(36_087_000, 6070) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -283,12 +283,12 @@ impl WeightInfo for BridgeWeight { /// The range of component `i` is `[128, 2048]`. fn receive_single_message_proof_with_dispatch(i: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_385 nanoseconds. - Weight::from_parts(54_919_468, 57170) - // Standard Error: 108 - .saturating_add(Weight::from_parts(3_286, 0).saturating_mul(i.into())) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 73_740 nanoseconds. + Weight::from_parts(74_788_229, 52645) + // Standard Error: 1_392 + .saturating_add(Weight::from_parts(302_332, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -312,10 +312,10 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_321 nanoseconds. - Weight::from_parts(54_478_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 34_049 nanoseconds. + Weight::from_parts(39_460_000, 52645) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -335,10 +335,10 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_two_messages_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_597 nanoseconds. - Weight::from_parts(69_267_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 44_030 nanoseconds. + Weight::from_parts(48_036_000, 52645) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -358,10 +358,10 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 64_079 nanoseconds. - Weight::from_parts(65_905_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 42_839 nanoseconds. + Weight::from_parts(45_052_000, 52645) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -381,10 +381,10 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_1_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 50_588 nanoseconds. - Weight::from_parts(53_544_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 33_925 nanoseconds. + Weight::from_parts(36_321_000, 52645) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -404,10 +404,10 @@ impl WeightInfo for () { /// 51655, mode: MaxEncodedLen) fn receive_single_message_proof_16_kb() -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 78_269 nanoseconds. - Weight::from_parts(81_748_000, 57170) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 50_591 nanoseconds. + Weight::from_parts(56_245_000, 52645) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -432,10 +432,10 @@ impl WeightInfo for () { /// mode: MaxEncodedLen) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `579` - // Estimated: `9584` - // Minimum execution time: 45_786 nanoseconds. - Weight::from_parts(47_382_000, 9584) + // Measured: `453` + // Estimated: `3530` + // Minimum execution time: 33_199 nanoseconds. + Weight::from_parts(34_349_000, 3530) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -460,10 +460,10 @@ impl WeightInfo for () { /// mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `9584` - // Minimum execution time: 44_544 nanoseconds. - Weight::from_parts(45_451_000, 9584) + // Measured: `470` + // Estimated: `3530` + // Minimum execution time: 32_221 nanoseconds. + Weight::from_parts(33_944_000, 3530) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -488,10 +488,10 @@ impl WeightInfo for () { /// mode: MaxEncodedLen) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `596` - // Estimated: `12124` - // Minimum execution time: 47_344 nanoseconds. - Weight::from_parts(48_311_000, 12124) + // Measured: `470` + // Estimated: `6070` + // Minimum execution time: 34_880 nanoseconds. + Weight::from_parts(36_087_000, 6070) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -513,12 +513,12 @@ impl WeightInfo for () { /// The range of component `i` is `[128, 2048]`. fn receive_single_message_proof_with_dispatch(i: u32) -> Weight { // Proof Size summary in bytes: - // Measured: `618` - // Estimated: `57170` - // Minimum execution time: 52_385 nanoseconds. - Weight::from_parts(54_919_468, 57170) - // Standard Error: 108 - .saturating_add(Weight::from_parts(3_286, 0).saturating_mul(i.into())) + // Measured: `428` + // Estimated: `52645` + // Minimum execution time: 73_740 nanoseconds. + Weight::from_parts(74_788_229, 52645) + // Standard Error: 1_392 + .saturating_add(Weight::from_parts(302_332, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/bridges/modules/parachains/src/mock.rs b/bridges/modules/parachains/src/mock.rs index dbb62845392d5..d5fdf37e36fd0 100644 --- a/bridges/modules/parachains/src/mock.rs +++ b/bridges/modules/parachains/src/mock.rs @@ -23,7 +23,7 @@ use frame_support::{ use sp_runtime::{ testing::H256, traits::{BlakeTwo256, Header as HeaderT}, - MultiSignature, + MultiSignature, StateVersion, }; use crate as pallet_bridge_parachains; @@ -60,6 +60,8 @@ impl Chain for Parachain1 { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -87,6 +89,8 @@ impl Chain for Parachain2 { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -114,6 +118,8 @@ impl Chain for Parachain3 { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -142,6 +148,8 @@ impl Chain for BigParachain { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } @@ -256,6 +264,8 @@ impl Chain for TestBridgedChain { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } @@ -289,6 +299,8 @@ impl Chain for OtherBridgedChain { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index 4c09bce56d73e..fb47fc6943927 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -36,7 +36,7 @@ use sp_core::H256; use sp_runtime::{ testing::Header as SubstrateHeader, traits::{BlakeTwo256, IdentityLookup}, - AccountId32, BuildStorage, + AccountId32, BuildStorage, StateVersion, }; use xcm::prelude::*; @@ -211,6 +211,8 @@ impl Chain for ThisChain { type Nonce = u64; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { u32::MAX } @@ -235,6 +237,8 @@ impl Chain for BridgedChain { type Nonce = u64; type Signature = sp_runtime::MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 4096 } diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index af2afb65a26a7..22b70d40c1d5e 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -25,7 +25,8 @@ use crate::justification::{ }; use bp_runtime::{ BasicOperatingMode, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, RawStorageProof, - StorageProofChecker, StorageProofError, UnderlyingChainProvider, + StorageProofChecker, StorageProofError, TrustedVecDb, UnderlyingChainProvider, UntrustedVecDb, + VecDbError, }; use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug}; @@ -48,6 +49,8 @@ pub enum HeaderChainError { UnknownHeader, /// Storage proof related error. StorageProof(StorageProofError), + /// Error generated by the `vec_db` module. + VecDb(VecDbError), } /// Header data that we're storing on-chain. @@ -78,6 +81,16 @@ impl StoredHeaderDataBuilder for H { pub trait HeaderChain { /// Returns state (storage) root of given finalized header. fn finalized_header_state_root(header_hash: HashOf) -> Option>; + /// Get a `TrustedVecDb` starting from an `UntrustedVecDb`. + fn verify_vec_db_storage( + header_hash: HashOf, + db: UntrustedVecDb, + ) -> Result { + let state_root = Self::finalized_header_state_root(header_hash) + .ok_or(HeaderChainError::UnknownHeader)?; + db.verify::>(C::STATE_VERSION, &state_root) + .map_err(HeaderChainError::VecDb) + } /// Get storage proof checker using finalized header. fn storage_proof_checker( header_hash: HashOf, @@ -409,7 +422,9 @@ mod tests { use super::*; use bp_runtime::ChainId; use frame_support::weights::Weight; - use sp_runtime::{testing::H256, traits::BlakeTwo256, DigestItem, MultiSignature}; + use sp_runtime::{ + testing::H256, traits::BlakeTwo256, DigestItem, MultiSignature, StateVersion, + }; struct TestChain; @@ -425,6 +440,8 @@ mod tests { type Nonce = u64; type Signature = MultiSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 0 } diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index c3f79b3ee388c..6914b42b65960 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -22,7 +22,7 @@ use bp_header_chain::HeaderChainError; use bp_runtime::{ messages::MessageDispatchResult, BasicOperatingMode, Chain, OperatingMode, RangeInclusiveExt, - StorageProofError, UnderlyingChainOf, UnderlyingChainProvider, + StorageProofError, UnderlyingChainOf, UnderlyingChainProvider, VecDbError, }; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::PalletError; @@ -486,14 +486,16 @@ pub enum VerificationError { InvalidMessageWeight, /// Declared messages count doesn't match actual value. MessagesCountMismatch, - /// Error returned while reading/decoding message data from the storage proof. - MessageStorage(StorageProofError), + /// Error returned while reading/decoding message data from the `VecDb`. + MessageStorage(VecDbError), /// The message is too large. MessageTooLarge, - /// Error returned while reading/decoding outbound lane data from the storage proof. - OutboundLaneStorage(StorageProofError), + /// Error returned while reading/decoding outbound lane data from the `VecDb`. + OutboundLaneStorage(VecDbError), /// Storage proof related error. StorageProof(StorageProofError), + /// `VecDb` related error. + VecDb(VecDbError), /// Custom error Other(#[codec(skip)] &'static str), } diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 369386e41b0cf..0db4eac79a750 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -24,7 +24,7 @@ use sp_runtime::{ AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, Verify, }, - FixedPointOperand, + FixedPointOperand, StateVersion, }; use sp_std::{fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec}; @@ -196,6 +196,10 @@ pub trait Chain: Send + Sync + 'static { /// Signature type, used on this chain. type Signature: Parameter + Verify; + /// Version of the state implementation used by this chain. This is directly related with the + /// `TrieLayout` configuration used by the storage. + const STATE_VERSION: StateVersion; + /// Get the maximum size (in bytes) of a Normal extrinsic at this chain. fn max_extrinsic_size() -> u32; /// Get the maximum weight (compute time) that a Normal extrinsic at this chain can use. @@ -223,6 +227,8 @@ where type Nonce = ::Nonce; type Signature = ::Signature; + const STATE_VERSION: StateVersion = ::STATE_VERSION; + fn max_extrinsic_size() -> u32 { ::max_extrinsic_size() } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index d13c9b40efa0b..a5477f0024702 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -45,6 +45,7 @@ pub use storage_proof::{ ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker, }; pub use storage_types::BoundedStorageValue; +pub use vec_db::{TrustedVecDb, UntrustedVecDb, VecDbError}; #[cfg(feature = "std")] pub use storage_proof::craft_valid_storage_proof; @@ -55,6 +56,7 @@ pub mod messages; mod chain; mod storage_proof; mod storage_types; +mod vec_db; // Re-export macro to avoid include paste dependency everywhere pub use sp_runtime::paste; diff --git a/bridges/primitives/runtime/src/vec_db.rs b/bridges/primitives/runtime/src/vec_db.rs new file mode 100644 index 0000000000000..6034e102bd305 --- /dev/null +++ b/bridges/primitives/runtime/src/vec_db.rs @@ -0,0 +1,332 @@ +// Copyright 2019-2023 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 . + +//! Logic for working with more efficient storage proofs. + +use frame_support::PalletError; +use sp_core::{storage::TrackedStorageKey, RuntimeDebug}; +use sp_runtime::{SaturatedConversion, StateVersion}; +use sp_std::{default::Default, vec, vec::Vec}; +use sp_trie::{ + generate_trie_proof, verify_trie_proof, LayoutV0, LayoutV1, StorageProof, TrieDBBuilder, + TrieHash, +}; + +use codec::{Decode, Encode}; +use hash_db::Hasher; +use scale_info::TypeInfo; +use trie_db::{DBValue, Trie}; + +use crate::{storage_proof::RawStorageProof, Size}; + +pub type RawStorageKey = Vec; + +/// Errors that can occur when interacting with `UntrustedVecDb` and `TrustedVecDb`. +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum VecDbError { + /// Call to `generate_trie_proof()` failed. + UnableToGenerateTrieProof, + /// Call to `verify_trie_proof()` failed. + InvalidProof, + /// The `Vec` entries weren't sorted as expected. + UnsortedEntries, + /// The provided key wasn't found. + UnavailableKey, + /// The value associated to the provided key is `None`. + EmptyVal, + /// Error decoding value associated to a provided key. + DecodeError, + /// At least one key in the `VecDb` wasn't read. + UnusedKey, +} + +/// Structure representing a key-value database stored as a sorted `Vec` of tuples. +/// +/// The structure also contains a proof of the fact that the key-value tuples are actually present +/// in the chain storage. +#[derive(Clone, Default, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct UntrustedVecDb { + proof: RawStorageProof, + db: Vec<(RawStorageKey, Option)>, +} + +impl UntrustedVecDb { + /// Creates a new instance of `UntrustedVecDb`. + pub fn try_new( + read_proof: StorageProof, + root: TrieHash>, + mut keys: Vec + Ord>, + ) -> Result { + // It's ok to use `LayoutV1` in this function, no matter the actual underlying layout, + // because we only perform read operations. When reading `LayoutV0` and `LayoutV1` lead to + // the same result. + let mem_db = read_proof.into_memory_db(); + let trie_db = TrieDBBuilder::>::new(&mem_db, &root).build(); + + let trie_proof = generate_trie_proof::, _, _, _>(&mem_db, root, &keys) + .map_err(|_| VecDbError::UnableToGenerateTrieProof)?; + + let mut entries = Vec::with_capacity(keys.len()); + keys.sort(); + for key in keys { + let val = trie_db.get(key.as_ref()).map_err(|_| VecDbError::UnavailableKey)?; + entries.push((key.as_ref().to_vec(), val)); + } + + Ok(Self { proof: trie_proof, db: entries }) + } + + /// Validates the contained `db` against the contained proof. If the `db` is valid, converts it + /// into a `TrustedVecDb`. + pub fn verify( + mut self, + state_version: StateVersion, + state_root: &TrieHash>, + ) -> Result { + // First we verify the proof for the `UntrustedVecDb`. + // Note that `verify_trie_proof()` also checks for duplicate keys and unused nodes. + match state_version { + StateVersion::V0 => + verify_trie_proof::, _, _, _>(state_root, &self.proof, &self.db), + StateVersion::V1 => + verify_trie_proof::, _, _, _>(state_root, &self.proof, &self.db), + } + .map_err(|_| VecDbError::InvalidProof)?; + + // Fill the `TrustedVecDb` + let mut trusted_db = Vec::with_capacity(self.db.len()); + let mut iter = self.db.drain(..).peekable(); + while let Some((key, val)) = iter.next() { + // Let's also make sure that the db is actually sorted. + if let Some((next_key, _)) = iter.peek() { + if next_key <= &key { + return Err(VecDbError::UnsortedEntries) + } + } + trusted_db.push((TrackedStorageKey::new(key), val)) + } + Ok(TrustedVecDb { db: trusted_db }) + } +} + +impl Size for UntrustedVecDb { + fn size(&self) -> u32 { + let proof_size = self.proof.iter().fold(0usize, |sum, node| sum.saturating_add(node.len())); + let entries_size = self.db.iter().fold(0usize, |sum, (key, value)| { + sum.saturating_add(key.len()) + .saturating_add(value.as_ref().unwrap_or(&vec![]).len()) + }); + + proof_size.saturating_add(entries_size).saturated_into() + } +} + +/// Structure representing a key-value database stored as a sorted `Vec` of tuples. +pub struct TrustedVecDb { + db: Vec<(TrackedStorageKey, Option)>, +} + +impl TrustedVecDb { + /// Returns a reference to the value corresponding to the key. + /// + /// Returns an error if the key doesn't exist. + pub fn get(&mut self, key: &impl AsRef<[u8]>) -> Result<&Option, VecDbError> { + let idx = self + .db + .binary_search_by(|(db_key, _)| db_key.key.as_slice().cmp(key.as_ref())) + .map_err(|_| VecDbError::UnavailableKey)?; + let (db_key, db_val) = self.db.get_mut(idx).ok_or(VecDbError::UnavailableKey)?; + db_key.add_read(); + Ok(db_val) + } + + /// Returns a reference to the value corresponding to the key. + /// + /// Returns an error if the key doesn't exist or if the value associated to it is `None`. + pub fn get_and_decode_mandatory( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result { + let val = self.get(key)?.as_ref().ok_or(VecDbError::EmptyVal)?; + D::decode(&mut &val[..]).map_err(|_| VecDbError::DecodeError) + } + + /// Returns a reference to the value corresponding to the key. + /// + /// Returns `None` if the key doesn't exist or if the value associated to it is `None`. + pub fn get_and_decode_optional( + &mut self, + key: &impl AsRef<[u8]>, + ) -> Result, VecDbError> { + match self.get_and_decode_mandatory(key) { + Ok(val) => Ok(Some(val)), + Err(VecDbError::UnavailableKey | VecDbError::EmptyVal) => Ok(None), + Err(e) => Err(e), + } + } + + /// Checks if each key was read. + pub fn ensure_no_unused_keys(&self) -> Result<(), VecDbError> { + for (key, _) in &self.db { + if !key.has_been_read() { + return Err(VecDbError::UnusedKey) + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::H256; + + use sp_state_machine::{prove_read, InMemoryBackend}; + + type Hasher = sp_core::Blake2Hasher; + + fn generate_untrusted_vec_db( + entries: Vec<(RawStorageKey, Option)>, + ) -> (H256, Result) { + let keys: Vec<_> = entries.iter().map(|(key, _)| key.clone()).collect(); + let entries: Vec<_> = + entries.iter().cloned().map(|(key, val)| (None, vec![(key, val)])).collect(); + let backend = InMemoryBackend::::from((entries, StateVersion::V1)); + let root = *backend.root(); + let read_proof = prove_read(backend, &keys).unwrap(); + + (root, UntrustedVecDb::try_new::(read_proof, root, keys)) + } + + #[test] + fn verify_succeeds_when_used_correctly() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![ + (b"key1".to_vec(), None), + (b"key2".to_vec(), Some(b"val2".to_vec())), + ]); + let db = maybe_db.unwrap(); + + assert!(db.verify::(StateVersion::V1, &root).is_ok()); + } + + #[test] + fn verify_fails_when_proof_contains_unneeded_nodes() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![ + (b"key1".to_vec(), Some(b"val1".to_vec().encode())), + (b"key2".to_vec(), Some(b"val2".to_vec().encode())), + ]); + let mut db = maybe_db.unwrap(); + assert!(db.db.pop().is_some()); + + assert!(matches!( + db.verify::(StateVersion::V1, &root), + Err(VecDbError::InvalidProof) + )); + } + + #[test] + fn verify_fails_when_db_contains_duplicate_nodes() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![(b"key".to_vec(), None)]); + let mut db = maybe_db.unwrap(); + db.db.push((b"key".to_vec(), None)); + + assert!(matches!( + db.verify::(StateVersion::V1, &root), + Err(VecDbError::InvalidProof) + )); + } + + #[test] + fn verify_fails_when_entries_are_not_sorted() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![ + (b"key1".to_vec(), Some(b"val1".to_vec().encode())), + (b"key2".to_vec(), Some(b"val2".to_vec().encode())), + ]); + let mut db = maybe_db.unwrap(); + db.db.reverse(); + + assert!(matches!( + db.verify::(StateVersion::V1, &root), + Err(VecDbError::UnsortedEntries) + )); + } + + #[test] + fn get_and_decode_mandatory_works() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![ + (b"key11".to_vec(), Some(b"val11".to_vec().encode())), + (b"key2".to_vec(), Some(b"val2".to_vec().encode())), + (b"key1".to_vec(), None), + (b"key15".to_vec(), Some(b"val15".to_vec())), + ]); + let db = maybe_db.unwrap(); + let mut trusted_db = db.verify::(StateVersion::V1, &root).unwrap(); + + assert!( + matches!(trusted_db.get_and_decode_mandatory::>(b"key11"), Ok(val) if val == b"val11".to_vec()) + ); + assert!( + matches!(trusted_db.get_and_decode_mandatory::>(b"key2"), Ok(val) if val == b"val2".to_vec()) + ); + assert!(matches!( + trusted_db.get_and_decode_mandatory::>(b"key1"), + Err(VecDbError::EmptyVal) + )); + assert!(matches!( + trusted_db.get_and_decode_mandatory::>(b"key15"), + Err(VecDbError::DecodeError) + )); + } + + #[test] + fn get_and_decode_optional_works() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![ + (b"key11".to_vec(), Some(b"val11".to_vec().encode())), + (b"key2".to_vec(), Some(b"val2".to_vec().encode())), + (b"key1".to_vec(), None), + (b"key15".to_vec(), Some(b"val15".to_vec())), + ]); + let db = maybe_db.unwrap(); + let mut trusted_db = db.verify::(StateVersion::V1, &root).unwrap(); + + assert!( + matches!(trusted_db.get_and_decode_optional::>(b"key11"), Ok(Some(val)) if val == + b"val11".to_vec()) + ); + assert!( + matches!(trusted_db.get_and_decode_optional::>(b"key2"), Ok(Some(val)) if val == b"val2".to_vec()) + ); + assert!(matches!(trusted_db.get_and_decode_optional::>(b"key1"), Ok(None))); + assert!(matches!( + trusted_db.get_and_decode_optional::>(b"key15"), + Err(VecDbError::DecodeError) + )); + } + + #[test] + fn ensure_no_unused_keys_works_correctly() { + let (root, maybe_db) = generate_untrusted_vec_db(vec![ + (b"key1".to_vec(), None), + (b"key2".to_vec(), Some(b"val2".to_vec())), + ]); + let db = maybe_db.unwrap(); + let mut trusted_db = db.verify::(StateVersion::V1, &root).unwrap(); + assert!(trusted_db.get(b"key1").is_ok()); + + assert!(matches!(trusted_db.ensure_no_unused_keys(), Err(VecDbError::UnusedKey))); + } +} diff --git a/bridges/relays/client-substrate/src/test_chain.rs b/bridges/relays/client-substrate/src/test_chain.rs index cfd241c022a26..991202e9874c7 100644 --- a/bridges/relays/client-substrate/src/test_chain.rs +++ b/bridges/relays/client-substrate/src/test_chain.rs @@ -24,7 +24,7 @@ use crate::{Chain, ChainWithBalances, ChainWithMessages}; use bp_messages::{ChainWithMessages as ChainWithMessagesBase, MessageNonce}; use bp_runtime::ChainId; -use frame_support::weights::Weight; +use frame_support::{sp_runtime::StateVersion, weights::Weight}; use std::time::Duration; /// Chain that may be used in tests. @@ -44,6 +44,8 @@ impl bp_runtime::Chain for TestChain { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { 100000 } @@ -100,6 +102,8 @@ impl bp_runtime::Chain for TestParachainBase { type Nonce = u32; type Signature = sp_runtime::testing::TestSignature; + const STATE_VERSION: StateVersion = StateVersion::V1; + fn max_extrinsic_size() -> u32 { unreachable!() } diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages_lane.rs index e3786dcdc5e31..909fa6b148a25 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_lane.rs @@ -643,13 +643,7 @@ where Weight::zero(), FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), - // we may use per-chain `EXTRA_STORAGE_PROOF_SIZE`, but since we don't need - // exact values, this global estimation is fine - storage_proof: vec![vec![ - 42u8; - pallet_bridge_messages::EXTRA_STORAGE_PROOF_SIZE - as usize - ]], + storage: Default::default(), lane: Default::default(), nonces_start: 1, nonces_end: messages as u64, diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs index 1f597e278da40..b8f51cd5c9326 100644 --- a/bridges/relays/lib-substrate-relay/src/messages_source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs @@ -35,7 +35,9 @@ use bp_messages::{ ChainWithMessages as _, InboundMessageDetails, LaneId, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, }; -use bp_runtime::{BasicOperatingMode, HeaderIdProvider}; +use bp_runtime::{ + BasicOperatingMode, HasherOf, HeaderIdProvider, RangeInclusiveExt, UntrustedVecDb, +}; use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; use codec::Encode; use frame_support::weights::Weight; @@ -54,6 +56,7 @@ use relay_substrate_client::{ }; use relay_utils::relay_loop::Client as RelayClient; use sp_core::Pair; +use sp_runtime::traits::Header; use std::ops::RangeInclusive; /// Intermediate message proof returned by the source Substrate node. Includes everything @@ -320,34 +323,33 @@ where ), SubstrateError, > { - let mut storage_keys = - Vec::with_capacity(nonces.end().saturating_sub(*nonces.start()) as usize + 1); - let mut message_nonce = *nonces.start(); - while message_nonce <= *nonces.end() { + let mut storage_keys = Vec::with_capacity(nonces.saturating_len() as usize); + for message_nonce in nonces.clone() { let message_key = bp_messages::storage_keys::message_key( P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, message_nonce, ); storage_keys.push(message_key); - message_nonce += 1; } if proof_parameters.outbound_state_proof_required { - storage_keys.push(bp_messages::storage_keys::outbound_lane_data_key( + storage_keys.push(outbound_lane_data_key( P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, )); } - let proof = self - .source_client - .prove_storage(id.1, storage_keys) - .await? - .into_iter_nodes() - .collect(); + let root = *self.source_client.header_by_hash(id.hash()).await?.state_root(); + let storage_proof = + self.source_client.prove_storage(id.hash(), storage_keys.clone()).await?; + let storage = + UntrustedVecDb::try_new::>(storage_proof, root, storage_keys) + .map_err(|e| { + SubstrateError::Custom(format!("Error generating messages storage: {:?}", e)) + })?; let proof = FromBridgedChainMessagesProof { bridged_header_hash: id.1, - storage_proof: proof, + storage, lane: self.lane_id, nonces_start: *nonces.start(), nonces_end: *nonces.end(),