mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 04:01:02 +00:00
only store header state root (pallet-bridge-grandpa) (#1699)
This commit is contained in:
committed by
Bastian Köcher
parent
b94bd8d46b
commit
7014046485
@@ -40,7 +40,7 @@ impl<
|
||||
|
||||
let best_finalized = crate::BestFinalized::<T, I>::get();
|
||||
let best_finalized_number = match best_finalized {
|
||||
Some((best_finalized_number, _)) => best_finalized_number,
|
||||
Some(best_finalized_id) => best_finalized_id.number(),
|
||||
None => return InvalidTransaction::Call.into(),
|
||||
};
|
||||
|
||||
@@ -66,6 +66,7 @@ mod tests {
|
||||
mock::{run_test, test_header, RuntimeCall, TestNumber, TestRuntime},
|
||||
BestFinalized,
|
||||
};
|
||||
use bp_runtime::HeaderId;
|
||||
use bp_test_utils::make_default_justification;
|
||||
|
||||
fn validate_block_submit(num: TestNumber) -> bool {
|
||||
@@ -81,7 +82,7 @@ mod tests {
|
||||
|
||||
fn sync_to_header_10() {
|
||||
let header10_hash = sp_core::H256::default();
|
||||
BestFinalized::<TestRuntime, ()>::put((10, header10_hash));
|
||||
BestFinalized::<TestRuntime, ()>::put(HeaderId(10, header10_hash));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -38,10 +38,11 @@
|
||||
|
||||
use storage_types::StoredAuthoritySet;
|
||||
|
||||
use bp_header_chain::{justification::GrandpaJustification, HeaderChain, InitializationData};
|
||||
use bp_runtime::{
|
||||
BlockNumberOf, BoundedStorageValue, Chain, HashOf, HasherOf, HeaderOf, OwnedBridgeModule,
|
||||
use bp_header_chain::{
|
||||
justification::GrandpaJustification, HeaderChain, InitializationData, StoredHeaderData,
|
||||
StoredHeaderDataBuilder,
|
||||
};
|
||||
use bp_runtime::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderId, HeaderOf, OwnedBridgeModule};
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use frame_support::{ensure, fail};
|
||||
use frame_system::ensure_signed;
|
||||
@@ -73,13 +74,15 @@ pub type BridgedChain<T, I> = <T as Config<I>>::BridgedChain;
|
||||
pub type BridgedBlockNumber<T, I> = BlockNumberOf<<T as Config<I>>::BridgedChain>;
|
||||
/// Block hash of the bridged chain.
|
||||
pub type BridgedBlockHash<T, I> = HashOf<<T as Config<I>>::BridgedChain>;
|
||||
/// Block id of the bridged chain.
|
||||
pub type BridgedBlockId<T, I> = HeaderId<BridgedBlockHash<T, I>, BridgedBlockNumber<T, I>>;
|
||||
/// Hasher of the bridged chain.
|
||||
pub type BridgedBlockHasher<T, I> = HasherOf<<T as Config<I>>::BridgedChain>;
|
||||
/// Header of the bridged chain.
|
||||
pub type BridgedHeader<T, I> = HeaderOf<<T as Config<I>>::BridgedChain>;
|
||||
/// Stored header of the bridged chain.
|
||||
pub type StoredBridgedHeader<T, I> =
|
||||
BoundedStorageValue<<T as Config<I>>::MaxBridgedHeaderSize, BridgedHeader<T, I>>;
|
||||
/// Header data of the bridged chain that is stored at this chain by this pallet.
|
||||
pub type BridgedStoredHeaderData<T, I> =
|
||||
StoredHeaderData<BridgedBlockNumber<T, I>, BridgedBlockHash<T, I>>;
|
||||
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
@@ -115,15 +118,6 @@ pub mod pallet {
|
||||
/// Max number of authorities at the bridged chain.
|
||||
#[pallet::constant]
|
||||
type MaxBridgedAuthorities: Get<u32>;
|
||||
/// Maximal size (in bytes) of the SCALE-encoded bridged chain header.
|
||||
///
|
||||
/// This constant must be selected with care. The pallet requires mandatory headers to be
|
||||
/// submitted to be able to proceed. Mandatory headers contain public keys of all GRANDPA
|
||||
/// authorities. E.g. for 1024 authorities, the size of encoded keys will be at least 32 KB.
|
||||
/// The same header may also contain other digest items as well, so some reserve here
|
||||
/// is required.
|
||||
#[pallet::constant]
|
||||
type MaxBridgedHeaderSize: Get<u32>;
|
||||
|
||||
/// Weights gathered through benchmarking.
|
||||
type WeightInfo: WeightInfo;
|
||||
@@ -178,11 +172,8 @@ pub mod pallet {
|
||||
finality_target
|
||||
);
|
||||
|
||||
let best_finalized = BestFinalized::<T, I>::get();
|
||||
let best_finalized =
|
||||
best_finalized.and_then(|(_, hash)| ImportedHeaders::<T, I>::get(hash));
|
||||
let best_finalized = match best_finalized {
|
||||
Some(best_finalized) => best_finalized,
|
||||
let best_finalized_number = match BestFinalized::<T, I>::get() {
|
||||
Some(best_finalized_id) => best_finalized_id.number(),
|
||||
None => {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
@@ -196,7 +187,7 @@ pub mod pallet {
|
||||
// We do a quick check here to ensure that our header chain is making progress and isn't
|
||||
// "travelling back in time" (which could be indicative of something bad, e.g a
|
||||
// hard-fork).
|
||||
ensure!(best_finalized.number() < number, <Error<T, I>>::OldHeader);
|
||||
ensure!(best_finalized_number < *number, <Error<T, I>>::OldHeader);
|
||||
|
||||
let authority_set = <CurrentAuthoritySet<T, I>>::get();
|
||||
let set_id = authority_set.set_id;
|
||||
@@ -204,20 +195,8 @@ pub mod pallet {
|
||||
|
||||
let is_authorities_change_enacted =
|
||||
try_enact_authority_change::<T, I>(&finality_target, set_id)?;
|
||||
let finality_target = StoredBridgedHeader::<T, I>::try_from_inner(*finality_target)
|
||||
.map_err(|e| {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"Size of header {:?} ({}) is larger that the configured value {}",
|
||||
hash,
|
||||
e.value_size,
|
||||
e.maximal_size,
|
||||
);
|
||||
|
||||
Error::<T, I>::TooLargeHeader
|
||||
})?;
|
||||
<RequestCount<T, I>>::mutate(|count| *count += 1);
|
||||
insert_header::<T, I>(finality_target, hash);
|
||||
insert_header::<T, I>(*finality_target, hash);
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"Successfully imported finalized header with hash {:?}!",
|
||||
@@ -302,8 +281,9 @@ pub mod pallet {
|
||||
|
||||
/// Hash of the best finalized header.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn best_finalized)]
|
||||
pub type BestFinalized<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, (BridgedBlockNumber<T, I>, BridgedBlockHash<T, I>), OptionQuery>;
|
||||
StorageValue<_, BridgedBlockId<T, I>, OptionQuery>;
|
||||
|
||||
/// A ring buffer of imported hashes. Ordered by the insertion time.
|
||||
#[pallet::storage]
|
||||
@@ -315,10 +295,10 @@ pub mod pallet {
|
||||
pub(super) type ImportedHashesPointer<T: Config<I>, I: 'static = ()> =
|
||||
StorageValue<_, u32, ValueQuery>;
|
||||
|
||||
/// Headers which have been imported into the pallet.
|
||||
/// Relevant fields of imported headers.
|
||||
#[pallet::storage]
|
||||
pub type ImportedHeaders<T: Config<I>, I: 'static = ()> =
|
||||
StorageMap<_, Identity, BridgedBlockHash<T, I>, StoredBridgedHeader<T, I>>;
|
||||
StorageMap<_, Identity, BridgedBlockHash<T, I>, BridgedStoredHeaderData<T, I>>;
|
||||
|
||||
/// The current GRANDPA Authority set.
|
||||
#[pallet::storage]
|
||||
@@ -394,8 +374,6 @@ pub mod pallet {
|
||||
AlreadyInitialized,
|
||||
/// Too many authorities in the set.
|
||||
TooManyAuthoritiesInSet,
|
||||
/// Too large header.
|
||||
TooLargeHeader,
|
||||
/// Error generated by the `OwnedBridgeModule` trait.
|
||||
BridgeModule(bp_runtime::OwnedBridgeModuleError),
|
||||
}
|
||||
@@ -489,13 +467,13 @@ pub mod pallet {
|
||||
/// Note this function solely takes care of updating the storage and pruning old entries,
|
||||
/// but does not verify the validity of such import.
|
||||
pub(crate) fn insert_header<T: Config<I>, I: 'static>(
|
||||
header: StoredBridgedHeader<T, I>,
|
||||
header: BridgedHeader<T, I>,
|
||||
hash: BridgedBlockHash<T, I>,
|
||||
) {
|
||||
let index = <ImportedHashesPointer<T, I>>::get();
|
||||
let pruning = <ImportedHashes<T, I>>::try_get(index);
|
||||
<BestFinalized<T, I>>::put((*header.number(), hash));
|
||||
<ImportedHeaders<T, I>>::insert(hash, header);
|
||||
<BestFinalized<T, I>>::put(HeaderId(*header.number(), hash));
|
||||
<ImportedHeaders<T, I>>::insert(hash, header.build());
|
||||
<ImportedHashes<T, I>>::insert(index, hash);
|
||||
|
||||
// Update ring buffer pointer and remove old header.
|
||||
@@ -526,21 +504,10 @@ pub mod pallet {
|
||||
Error::TooManyAuthoritiesInSet
|
||||
})?;
|
||||
let initial_hash = header.hash();
|
||||
let header = StoredBridgedHeader::<T, I>::try_from_inner(*header).map_err(|e| {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"Failed to initialize bridge. Size of header {:?} ({}) is larger that the configured value {}",
|
||||
initial_hash,
|
||||
e.value_size,
|
||||
e.maximal_size,
|
||||
);
|
||||
|
||||
Error::<T, I>::TooLargeHeader
|
||||
})?;
|
||||
|
||||
<InitialHash<T, I>>::put(initial_hash);
|
||||
<ImportedHashesPointer<T, I>>::put(0);
|
||||
insert_header::<T, I>(header, initial_hash);
|
||||
insert_header::<T, I>(*header, initial_hash);
|
||||
|
||||
<CurrentAuthoritySet<T, I>>::put(authority_set);
|
||||
|
||||
@@ -568,34 +535,19 @@ pub mod pallet {
|
||||
Default::default(),
|
||||
);
|
||||
let hash = header.hash();
|
||||
insert_header::<T, I>(
|
||||
StoredBridgedHeader::<T, I>::try_from_inner(header)
|
||||
.expect("only used from benchmarks; benchmarks are correct; qed"),
|
||||
hash,
|
||||
);
|
||||
insert_header::<T, I>(header, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config<I>, I: 'static> Pallet<T, I> {
|
||||
/// Get the best finalized header the pallet knows of.
|
||||
pub fn best_finalized() -> Option<BridgedHeader<T, I>> {
|
||||
let (_, hash) = <BestFinalized<T, I>>::get()?;
|
||||
<ImportedHeaders<T, I>>::get(hash).map(|h| h.into_inner())
|
||||
}
|
||||
|
||||
/// Check if a particular header is known to the bridge pallet.
|
||||
pub fn is_known_header(hash: BridgedBlockHash<T, I>) -> bool {
|
||||
<ImportedHeaders<T, I>>::contains_key(hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bridge GRANDPA pallet as header chain.
|
||||
pub type GrandpaChainHeaders<T, I> = Pallet<T, I>;
|
||||
|
||||
impl<T: Config<I>, I: 'static> HeaderChain<BridgedChain<T, I>> for GrandpaChainHeaders<T, I> {
|
||||
fn finalized_header(hash: HashOf<BridgedChain<T, I>>) -> Option<HeaderOf<BridgedChain<T, I>>> {
|
||||
ImportedHeaders::<T, I>::get(hash).map(|h| h.into_inner())
|
||||
fn finalized_header_state_root(
|
||||
header_hash: HashOf<BridgedChain<T, I>>,
|
||||
) -> Option<HashOf<BridgedChain<T, I>>> {
|
||||
ImportedHeaders::<T, I>::get(header_hash).map(|h| h.state_root)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,7 +605,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::mock::{
|
||||
run_test, test_header, RuntimeOrigin, TestHeader, TestNumber, TestRuntime,
|
||||
MAX_BRIDGED_AUTHORITIES, MAX_HEADER_SIZE,
|
||||
MAX_BRIDGED_AUTHORITIES,
|
||||
};
|
||||
use bp_runtime::BasicOperatingMode;
|
||||
use bp_test_utils::{
|
||||
@@ -742,10 +694,6 @@ mod tests {
|
||||
Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] }
|
||||
}
|
||||
|
||||
fn large_digest() -> Digest {
|
||||
Digest { logs: vec![DigestItem::Other(vec![42; MAX_HEADER_SIZE as _])] }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_root_or_owner_origin_can_initialize_pallet() {
|
||||
run_test(|| {
|
||||
@@ -808,25 +756,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn init_fails_if_header_is_too_large() {
|
||||
run_test(|| {
|
||||
let mut genesis = test_header(0);
|
||||
genesis.digest = large_digest();
|
||||
let init_data = InitializationData {
|
||||
header: Box::new(genesis),
|
||||
authority_list: authority_list(),
|
||||
set_id: 1,
|
||||
operating_mode: BasicOperatingMode::Normal,
|
||||
};
|
||||
|
||||
assert_noop!(
|
||||
Pallet::<TestRuntime>::initialize(RuntimeOrigin::root(), init_data),
|
||||
Error::<TestRuntime>::TooLargeHeader,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pallet_rejects_transactions_if_halted() {
|
||||
run_test(|| {
|
||||
@@ -1073,31 +1002,6 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn importing_header_rejects_header_if_it_is_too_large() {
|
||||
run_test(|| {
|
||||
initialize_substrate_bridge();
|
||||
|
||||
// Need to update the header digest to indicate that our header signals an authority set
|
||||
// change. However, the change doesn't happen until the next block.
|
||||
let mut header = test_header(2);
|
||||
header.digest = large_digest();
|
||||
|
||||
// Create a valid justification for the header
|
||||
let justification = make_default_justification(&header);
|
||||
|
||||
// Should not be allowed to import this header
|
||||
assert_err!(
|
||||
Pallet::<TestRuntime>::submit_finality_proof(
|
||||
RuntimeOrigin::signed(1),
|
||||
Box::new(header),
|
||||
justification
|
||||
),
|
||||
<Error<TestRuntime>>::TooLargeHeader
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() {
|
||||
run_test(|| {
|
||||
@@ -1121,11 +1025,8 @@ mod tests {
|
||||
header.set_state_root(state_root);
|
||||
|
||||
let hash = header.hash();
|
||||
<BestFinalized<TestRuntime>>::put((2, hash));
|
||||
<ImportedHeaders<TestRuntime>>::insert(
|
||||
hash,
|
||||
StoredBridgedHeader::<TestRuntime, ()>::try_from_inner(header).unwrap(),
|
||||
);
|
||||
<BestFinalized<TestRuntime>>::put(HeaderId(2, hash));
|
||||
<ImportedHeaders<TestRuntime>>::insert(hash, header.build());
|
||||
|
||||
assert_ok!(
|
||||
Pallet::<TestRuntime>::parse_finalized_storage_proof(hash, storage_proof, |_| (),),
|
||||
@@ -1220,7 +1121,7 @@ mod tests {
|
||||
run_test(|| {
|
||||
initialize_substrate_bridge();
|
||||
assert_ok!(submit_finality_proof(1));
|
||||
let first_header = Pallet::<TestRuntime>::best_finalized().unwrap();
|
||||
let first_header_hash = Pallet::<TestRuntime>::best_finalized().unwrap().hash();
|
||||
next_block();
|
||||
|
||||
assert_ok!(submit_finality_proof(2));
|
||||
@@ -1235,8 +1136,8 @@ mod tests {
|
||||
assert_ok!(submit_finality_proof(6));
|
||||
|
||||
assert!(
|
||||
!Pallet::<TestRuntime>::is_known_header(first_header.hash()),
|
||||
"First header should be pruned."
|
||||
!ImportedHeaders::<TestRuntime, ()>::contains_key(first_header_hash),
|
||||
"First header should be pruned.",
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
|
||||
|
||||
pub const MAX_BRIDGED_AUTHORITIES: u32 = 2048;
|
||||
pub const MAX_HEADER_SIZE: u32 = 65536;
|
||||
|
||||
use crate as grandpa;
|
||||
|
||||
@@ -94,7 +93,6 @@ impl grandpa::Config for TestRuntime {
|
||||
type MaxRequests = MaxRequests;
|
||||
type HeadersToKeep = HeadersToKeep;
|
||||
type MaxBridgedAuthorities = frame_support::traits::ConstU32<MAX_BRIDGED_AUTHORITIES>;
|
||||
type MaxBridgedHeaderSize = frame_support::traits::ConstU32<MAX_HEADER_SIZE>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user