Skip to content
This repository has been archived by the owner on Feb 29, 2024. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Guantong committed Apr 19, 2023
1 parent b7838f8 commit 88606cb
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 146 deletions.
5 changes: 3 additions & 2 deletions modules/grandpa/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,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(),
};

Expand All @@ -69,6 +69,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 {
Expand All @@ -84,7 +85,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]
Expand Down
163 changes: 32 additions & 131 deletions modules/grandpa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ mod storage_types;
// crates.io
use finality_grandpa::voter_set::VoterSet;
// darwinia-network
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 storage_types::StoredAuthoritySet;
// paritytech
use frame_support::{ensure, fail, log};
Expand All @@ -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 {
Expand Down Expand Up @@ -117,15 +120,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;
Expand Down Expand Up @@ -182,11 +176,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,
Expand All @@ -200,28 +191,16 @@ 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;
verify_justification::<T, I>(&justification, hash, *number, authority_set.into())?;

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 {:?}!",
Expand Down Expand Up @@ -309,8 +288,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]
Expand All @@ -322,10 +302,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]
Expand Down Expand Up @@ -401,8 +381,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),
}
Expand Down Expand Up @@ -496,13 +474,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.
Expand Down Expand Up @@ -533,21 +511,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);

Expand All @@ -574,35 +541,20 @@ 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);
}
}
}
pub use pallet::*;

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)
}
}

Expand Down Expand Up @@ -660,7 +612,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::{
Expand Down Expand Up @@ -749,10 +701,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(|| {
Expand Down Expand Up @@ -815,25 +763,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(|| {
Expand Down Expand Up @@ -1080,31 +1009,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(|| {
Expand All @@ -1128,11 +1032,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, |_| (),),
Expand Down Expand Up @@ -1227,7 +1128,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));
Expand All @@ -1242,8 +1143,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.",
);
})
}
Expand Down
2 changes: 0 additions & 2 deletions modules/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ type Block = MockBlock<TestRuntime>;
type UncheckedExtrinsic = MockUncheckedExtrinsic<TestRuntime>;

pub const MAX_BRIDGED_AUTHORITIES: u32 = 2048;
pub const MAX_HEADER_SIZE: u32 = 65536;

frame_support::construct_runtime! {
pub enum TestRuntime where
Expand Down Expand Up @@ -96,7 +95,6 @@ impl grandpa::Config for TestRuntime {
type BridgedChain = TestBridgedChain;
type HeadersToKeep = HeadersToKeep;
type MaxBridgedAuthorities = frame_support::traits::ConstU32<MAX_BRIDGED_AUTHORITIES>;
type MaxBridgedHeaderSize = frame_support::traits::ConstU32<MAX_HEADER_SIZE>;
type MaxRequests = MaxRequests;
type WeightInfo = ();
}
Expand Down
7 changes: 4 additions & 3 deletions modules/parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ pub mod pallet {
>::get(relay_block_hash)
.ok_or(Error::<T, I>::UnknownRelayChainBlock)?;
ensure!(
*relay_block.number() == relay_block_number,
relay_block.number == relay_block_number,
Error::<T, I>::InvalidRelayChainBlockNumber,
);

Expand Down Expand Up @@ -612,9 +612,10 @@ pub struct ParachainHeaders<T, I, C>(PhantomData<(T, I, C)>);
impl<T: Config<I>, I: 'static, C: Parachain<Hash = ParaHash>> HeaderChain<C>
for ParachainHeaders<T, I, C>
{
fn finalized_header(hash: HashOf<C>) -> Option<HeaderOf<C>> {
fn finalized_header_state_root(hash: HashOf<C>) -> Option<HashOf<C>> {
Pallet::<T, I>::parachain_head(ParaId(C::PARACHAIN_ID), hash)
.and_then(|head| Decode::decode(&mut &head.0[..]).ok())
.and_then(|head| HeaderOf::<C>::decode(&mut &head.0[..]).ok())
.map(|h| *h.state_root())
}
}

Expand Down
Loading

0 comments on commit 88606cb

Please sign in to comment.