Newer
Older
header.digest = forced_change_log(0);
// Create a valid justification for the header
let justification = make_default_justification(&header);
// Should not be allowed to import this header
assert_err!(
RuntimeOrigin::signed(1),
<Error<TestRuntime>>::UnsupportedScheduledChange
);
})
}
Svyatoslav Nikolsky
committed
#[test]
fn importing_header_rejects_header_with_too_many_authorities() {
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 = many_authorities_log();
// 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),
Svyatoslav Nikolsky
committed
Box::new(header),
justification
),
<Error<TestRuntime>>::TooManyAuthoritiesInSet
);
});
}
#[test]
fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() {
run_test(|| {
assert_noop!(
Pallet::<TestRuntime>::parse_finalized_storage_proof(
bp_header_chain::HeaderChainError::UnknownHeader,
);
});
}
#[test]
fn parse_finalized_storage_accepts_valid_proof() {
run_test(|| {
let (state_root, storage_proof) = bp_runtime::craft_valid_storage_proof();
let mut header = test_header(2);
header.set_state_root(state_root);
let hash = header.hash();
<BestFinalized<TestRuntime>>::put(HeaderId(2, hash));
<ImportedHeaders<TestRuntime>>::insert(hash, header.build());
Pallet::<TestRuntime>::parse_finalized_storage_proof(hash, storage_proof, |_| (),),
(),
);
});
}
#[test]
fn rate_limiter_disallows_imports_once_limit_is_hit_in_single_block() {
run_test(|| {
initialize_substrate_bridge();
assert_ok!(submit_finality_proof(1));
assert_ok!(submit_finality_proof(2));
assert_err!(submit_finality_proof(3), <Error<TestRuntime>>::TooManyRequests);
})
}
#[test]
fn rate_limiter_invalid_requests_do_not_count_towards_request_count() {
run_test(|| {
let submit_invalid_request = || {
let mut invalid_justification = make_default_justification(&header);
invalid_justification.round = 42;
RuntimeOrigin::signed(1),
Box::new(header),
invalid_justification,
)
};
initialize_substrate_bridge();
for _ in 0..<TestRuntime as Config>::MaxRequests::get() + 1 {
// Notice that the error here *isn't* `TooManyRequests`
assert_err!(submit_invalid_request(), <Error<TestRuntime>>::InvalidJustification);
}
// Can still submit `MaxRequests` requests afterwards
assert_ok!(submit_finality_proof(1));
assert_ok!(submit_finality_proof(2));
assert_err!(submit_finality_proof(3), <Error<TestRuntime>>::TooManyRequests);
fn rate_limiter_allows_request_after_new_block_has_started() {
run_test(|| {
initialize_substrate_bridge();
assert_ok!(submit_finality_proof(1));
assert_ok!(submit_finality_proof(2));
assert_ok!(submit_finality_proof(3));
fn rate_limiter_disallows_imports_once_limit_is_hit_across_different_blocks() {
run_test(|| {
initialize_substrate_bridge();
assert_ok!(submit_finality_proof(1));
assert_ok!(submit_finality_proof(2));
assert_ok!(submit_finality_proof(3));
assert_err!(submit_finality_proof(4), <Error<TestRuntime>>::TooManyRequests);
fn rate_limiter_allows_max_requests_after_long_time_with_no_activity() {
run_test(|| {
initialize_substrate_bridge();
assert_ok!(submit_finality_proof(1));
assert_ok!(submit_finality_proof(2));
next_block();
next_block();
next_block();
assert_ok!(submit_finality_proof(5));
assert_ok!(submit_finality_proof(7));
#[test]
fn should_prune_headers_over_headers_to_keep_parameter() {
run_test(|| {
initialize_substrate_bridge();
assert_ok!(submit_finality_proof(1));
let first_header_hash = Pallet::<TestRuntime>::best_finalized().unwrap().hash();
next_block();
assert_ok!(submit_finality_proof(2));
next_block();
assert_ok!(submit_finality_proof(3));
next_block();
assert_ok!(submit_finality_proof(4));
next_block();
assert_ok!(submit_finality_proof(5));
next_block();
assert_ok!(submit_finality_proof(6));
assert!(
!ImportedHeaders::<TestRuntime, ()>::contains_key(first_header_hash),
"First header should be pruned.",
Svyatoslav Nikolsky
committed
#[test]
fn storage_keys_computed_properly() {
Svyatoslav Nikolsky
committed
assert_eq!(
PalletOperatingMode::<TestRuntime>::storage_value_final_key().to_vec(),
bp_header_chain::storage_keys::pallet_operating_mode_key("Grandpa").0,
Svyatoslav Nikolsky
committed
);
Svyatoslav Nikolsky
committed
assert_eq!(
BestFinalized::<TestRuntime>::storage_value_final_key().to_vec(),
Svyatoslav Nikolsky
committed
bp_header_chain::storage_keys::best_finalized_key("Grandpa").0,
Svyatoslav Nikolsky
committed
);
}
#[test]
fn test_bridge_grandpa_call_is_correctly_defined() {
let header = test_header(0);
let init_data = InitializationData {
header: Box::new(header.clone()),
authority_list: authority_list(),
set_id: 1,
operating_mode: BasicOperatingMode::Normal,
};
let justification = make_default_justification(&header);
let direct_initialize_call =
Call::<TestRuntime>::initialize { init_data: init_data.clone() };
let indirect_initialize_call = BridgeGrandpaCall::<TestHeader>::initialize { init_data };
assert_eq!(direct_initialize_call.encode(), indirect_initialize_call.encode());
let direct_submit_finality_proof_call = Call::<TestRuntime>::submit_finality_proof {
finality_target: Box::new(header.clone()),
justification: justification.clone(),
};
let indirect_submit_finality_proof_call =
BridgeGrandpaCall::<TestHeader>::submit_finality_proof {
finality_target: Box::new(header),
justification,
};
assert_eq!(
direct_submit_finality_proof_call.encode(),
indirect_submit_finality_proof_call.encode()
);
}
generate_owned_bridge_module_tests!(BasicOperatingMode::Normal, BasicOperatingMode::Halted);
#[test]
fn maybe_headers_to_keep_returns_correct_value() {
assert_eq!(MaybeHeadersToKeep::<TestRuntime, ()>::get(), Some(mock::HeadersToKeep::get()));
}