Skip to content
lib.rs 38.5 KiB
Newer Older
				Pallet::<TestRuntime>::submit_finality_proof(
					Box::new(header),
					justification
				),
				<Error<TestRuntime>>::TooManyAuthoritiesInSet
			);
		});
	}

	#[test]
	fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() {
		run_test(|| {
			assert_noop!(
Hernando Castano's avatar
Hernando Castano committed
				Pallet::<TestRuntime>::parse_finalized_storage_proof(
					Default::default(),
					sp_trie::StorageProof::new(vec![]),
					|_| (),
				),
				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());
Hernando Castano's avatar
Hernando Castano committed
				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);
	fn rate_limiter_invalid_requests_do_not_count_towards_request_count() {
		run_test(|| {
			let submit_invalid_request = || {
				let header = test_header(1);
				let mut invalid_justification = make_default_justification(&header);
				invalid_justification.round = 42;
hacpy's avatar
hacpy committed
				Pallet::<TestRuntime>::submit_finality_proof(
hacpy's avatar
hacpy committed
					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.",
			PalletOperatingMode::<TestRuntime>::storage_value_final_key().to_vec(),
			bp_header_chain::storage_keys::pallet_operating_mode_key("Grandpa").0,
		assert_eq!(
			BestFinalized::<TestRuntime>::storage_value_final_key().to_vec(),
			bp_header_chain::storage_keys::best_finalized_key("Grandpa").0,
	#[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(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);