Skip to content
lib.rs 74.5 KiB
Newer Older
				..Default::default()
			};
			let len = 0_usize;

			let reset_check_weight = |i, f, s| {
				AllExtrinsicsWeight::put(s);
				let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, i, len);
				if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
			};

			reset_check_weight(&small, false, 0);
			reset_check_weight(&medium, false, 0);
			reset_check_weight(&big, true, 1);
	#[test]
	fn signed_ext_check_weight_refund_works() {
		new_test_ext().execute_with(|| {
			// This is half of the max block weight
			let info = DispatchInfo { weight: 512, ..Default::default() };
			let post_info = PostDispatchInfo { actual_weight: Some(128), };
			let len = 0_usize;

			// We allow 75% for normal transaction, so we put 25% - extrinsic base weight
			AllExtrinsicsWeight::put(256 - <Test as Trait>::ExtrinsicBaseWeight::get());

			let pre = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap();
			assert_eq!(AllExtrinsicsWeight::get().unwrap(), info.weight + 256);

			assert!(
				CheckWeight::<Test>::post_dispatch(pre, &info, &post_info, len, &Ok(()))
				.is_ok()
			);
			assert_eq!(
				AllExtrinsicsWeight::get().unwrap(),
				post_info.actual_weight.unwrap() + 256,
			);
		})
	}

	#[test]
	fn signed_ext_check_weight_actual_weight_higher_than_max_is_capped() {
		new_test_ext().execute_with(|| {
			let info = DispatchInfo { weight: 512, ..Default::default() };
			let post_info = PostDispatchInfo { actual_weight: Some(700), };
			let len = 0_usize;

			AllExtrinsicsWeight::put(128);

			let pre = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &info, len).unwrap();
			assert_eq!(
				AllExtrinsicsWeight::get().unwrap(),
				info.weight + 128 + <Test as Trait>::ExtrinsicBaseWeight::get(),
			);

			assert!(
				CheckWeight::<Test>::post_dispatch(pre, &info, &post_info, len, &Ok(()))
				.is_ok()
			);
			assert_eq!(
				AllExtrinsicsWeight::get().unwrap(),
				info.weight + 128 + <Test as Trait>::ExtrinsicBaseWeight::get(),
			);
	fn zero_weight_extrinsic_still_has_base_weight() {
		new_test_ext().execute_with(|| {
			let free = DispatchInfo { weight: 0, ..Default::default() };
			let len = 0_usize;

			// Initial weight from `BlockExecutionWeight`
			assert_eq!(System::all_extrinsics_weight(), <Test as Trait>::BlockExecutionWeight::get());
			let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &free, len);
			assert!(r.is_ok());
			assert_eq!(
				System::all_extrinsics_weight(),
				<Test as Trait>::ExtrinsicBaseWeight::get() + <Test as Trait>::BlockExecutionWeight::get()
			);
	fn max_extrinsic_weight_is_allowed_but_nothing_more() {
		// Dispatch Class Normal
		new_test_ext().execute_with(|| {
			let one = DispatchInfo { weight: 1, ..Default::default() };
			let max = DispatchInfo { weight: System::max_extrinsic_weight(DispatchClass::Normal), ..Default::default() };
			let len = 0_usize;

			assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max, len));
			assert_err!(
				CheckWeight::<Test>::do_pre_dispatch(&one, len),
				InvalidTransaction::ExhaustsResources,
			);
			// Weight should be 75% of 1024 (max block weight)
			assert_eq!(System::all_extrinsics_weight(), 768);
		});

		// Dispatch Class Operational
		new_test_ext().execute_with(|| {
			let one = DispatchInfo {
				weight: 1,
				class: DispatchClass::Operational,
				..Default::default()
			};
			let max = DispatchInfo {
				weight: System::max_extrinsic_weight(DispatchClass::Operational),
				class: DispatchClass::Operational,
				..Default::default()
			};
			let len = 0_usize;

			assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max, len));
			assert_err!(
				CheckWeight::<Test>::do_pre_dispatch(&one, len),
				InvalidTransaction::ExhaustsResources,
			);
			// Weight should be 100% of max block weight
			assert_eq!(System::all_extrinsics_weight(), <Test as Trait>::MaximumBlockWeight::get());
		});
	}

	#[test]
	fn mandatory_extrinsic_doesnt_care_about_limits() {
		new_test_ext().execute_with(|| {
			let max = DispatchInfo {
				weight: Weight::max_value(),
				class: DispatchClass::Mandatory,
				..Default::default()
			};
			let len = 0_usize;

			assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max, len));
			assert_eq!(System::all_extrinsics_weight(), Weight::max_value());
			assert!(System::all_extrinsics_weight() > <Test as Trait>::MaximumBlockWeight::get());
		});
	}

	#[test]
	fn register_extra_weight_unchecked_doesnt_care_about_limits() {
		new_test_ext().execute_with(|| {
			System::register_extra_weight_unchecked(Weight::max_value());
			assert_eq!(System::all_extrinsics_weight(), Weight::max_value());
			assert!(System::all_extrinsics_weight() > <Test as Trait>::MaximumBlockWeight::get());
		});
	}

	#[test]
	fn full_block_with_normal_and_operational() {
		new_test_ext().execute_with(|| {
			// Max block is 1024
			// Max normal is 768 (75%)
			// 10 is taken for block execution weight
			// So normal extrinsic can be 758 weight (-5 for base extrinsic weight)
			// And Operational can be 256 to produce a full block (-5 for base)

			assert_eq!(System::max_extrinsic_weight(DispatchClass::Normal), 753);

			let max_normal = DispatchInfo { weight: 753, ..Default::default() };
			let rest_operational = DispatchInfo { weight: 251, class: DispatchClass::Operational, ..Default::default() };

			let len = 0_usize;

			assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&max_normal, len));
			assert_eq!(System::all_extrinsics_weight(), 768);
			assert_ok!(CheckWeight::<Test>::do_pre_dispatch(&rest_operational, len));
			assert_eq!(<Test as Trait>::MaximumBlockWeight::get(), 1024);
			assert_eq!(System::all_extrinsics_weight(), <Test as Trait>::MaximumBlockWeight::get());
		});
	}

	#[test]
	fn signed_ext_check_weight_works_operational_tx() {
		new_test_ext().execute_with(|| {
			let normal = DispatchInfo { weight: 100, ..Default::default() };
			let op = DispatchInfo { weight: 100, class: DispatchClass::Operational, pays_fee: Pays::Yes };
			let len = 0_usize;
Kian Peymani's avatar
Kian Peymani committed
			let normal_limit = normal_weight_limit();

			// given almost full block
Kian Peymani's avatar
Kian Peymani committed
			AllExtrinsicsWeight::put(normal_limit);
			// will not fit.
			assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &normal, len).is_err());
			assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &op, len).is_ok());

			// likewise for length limit.
			let len = 100_usize;
Kian Peymani's avatar
Kian Peymani committed
			AllExtrinsicsLen::put(normal_length_limit());
			assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &normal, len).is_err());
			assert!(CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, &op, len).is_ok());
		})
	}

	#[test]
	fn signed_ext_check_weight_priority_works() {
		new_test_ext().execute_with(|| {
			let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes };
			let op = DispatchInfo { weight: 100, class: DispatchClass::Operational, pays_fee: Pays::Yes };
			let len = 0_usize;

			let priority = CheckWeight::<Test>(PhantomData)
				.validate(&1, CALL, &normal, len)
				.unwrap()
				.priority;
			assert_eq!(priority, 100);

			let priority = CheckWeight::<Test>(PhantomData)
				.validate(&1, CALL, &op, len)
				.unwrap()
				.priority;
			assert_eq!(priority, u64::max_value());
		})
	}

	#[test]
	fn signed_ext_check_weight_block_size_works() {
		new_test_ext().execute_with(|| {
Kian Peymani's avatar
Kian Peymani committed
			let normal = DispatchInfo::default();
			let normal_limit = normal_weight_limit() as usize;
			let reset_check_weight = |tx, s, f| {
				AllExtrinsicsLen::put(0);
				let r = CheckWeight::<Test>(PhantomData).pre_dispatch(&1, CALL, tx, s);
				if f { assert!(r.is_err()) } else { assert!(r.is_ok()) }
			};

			reset_check_weight(&normal, normal_limit - 1, false);
			reset_check_weight(&normal, normal_limit, false);
			reset_check_weight(&normal, normal_limit + 1, true);
Kian Peymani's avatar
Kian Peymani committed

			// Operational ones don't have this limit.
			let op = DispatchInfo { weight: 0, class: DispatchClass::Operational, pays_fee: Pays::Yes };
			reset_check_weight(&op, normal_limit, false);
			reset_check_weight(&op, normal_limit + 100, false);
			reset_check_weight(&op, 1024, false);
			reset_check_weight(&op, 1025, true);
		})
	}

	#[test]
	fn signed_ext_check_era_should_work() {
		new_test_ext().execute_with(|| {
			// future
			assert_eq!(
				CheckEra::<Test>::from(Era::mortal(4, 2)).additional_signed().err().unwrap(),
				InvalidTransaction::AncientBirthBlock.into(),
			);

			// correct
			System::set_block_number(13);
			<BlockHash<Test>>::insert(12, H256::repeat_byte(1));
			assert!(CheckEra::<Test>::from(Era::mortal(4, 12)).additional_signed().is_ok());
		})
	}

	#[test]
	fn signed_ext_check_era_should_change_longevity() {
		new_test_ext().execute_with(|| {
			let normal = DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes };
			let len = 0_usize;
			let ext = (
				CheckWeight::<Test>(PhantomData),
				CheckEra::<Test>::from(Era::mortal(16, 256)),
			);
			System::set_block_number(17);
			<BlockHash<Test>>::insert(16, H256::repeat_byte(1));

			assert_eq!(ext.validate(&1, CALL, &normal, len).unwrap().longevity, 15);


	#[test]
	fn set_code_checks_works() {
		struct CallInWasm(Vec<u8>);

		impl sp_core::traits::CallInWasm for CallInWasm {
			fn call_in_wasm(
				&self,
				_: &[u8],
				_: &str,
				_: &[u8],
				_: &mut dyn sp_externalities::Externalities,
				_: sp_core::traits::MissingHostFunctions,
			) -> Result<Vec<u8>, String> {
				Ok(self.0.clone())
			}
		}

		let test_data = vec![
			("test", 1, 2, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
			("test", 1, 1, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
			("test2", 1, 1, Err(Error::<Test>::InvalidSpecName)),
			("test", 2, 1, Ok(())),
			("test", 0, 1, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
			("test", 1, 0, Err(Error::<Test>::SpecVersionNeedsToIncrease)),
		];

		for (spec_name, spec_version, impl_version, expected) in test_data.into_iter() {
			let version = RuntimeVersion {
				spec_name: spec_name.into(),
				spec_version,
				impl_version,
				..Default::default()
			};
			let call_in_wasm = CallInWasm(version.encode());

			let mut ext = new_test_ext();
			ext.register_extension(sp_core::traits::CallInWasmExt::new(call_in_wasm));
			ext.execute_with(|| {
				let res = System::set_code(
					RawOrigin::Root.into(),
					vec![1, 2, 3, 4],
				);

				assert_eq!(expected.map_err(DispatchError::from), res);
			});
		}
	}

	#[test]
	fn set_code_with_real_wasm_blob() {
		let executor = substrate_test_runtime_client::new_native_executor();
		let mut ext = new_test_ext();
		ext.register_extension(sp_core::traits::CallInWasmExt::new(executor));
		ext.execute_with(|| {
			System::set_code(
				RawOrigin::Root.into(),
				substrate_test_runtime_client::runtime::WASM_BINARY.to_vec(),
			).unwrap();
				vec![EventRecord { phase: Phase::Initialization, event: 102u16, topics: vec![] }],
		});
	}

	#[test]
	fn runtime_upgraded_with_set_storage() {
		let executor = substrate_test_runtime_client::new_native_executor();
		let mut ext = new_test_ext();
		ext.register_extension(sp_core::traits::CallInWasmExt::new(executor));
		ext.execute_with(|| {
			System::set_storage(
				RawOrigin::Root.into(),
				vec![(
					well_known_keys::CODE.to_vec(),
					substrate_test_runtime_client::runtime::WASM_BINARY.to_vec()
				)],
			).unwrap();

	#[test]
	fn events_not_emitted_during_genesis() {
		new_test_ext().execute_with(|| {
			// Block Number is zero at genesis
			assert!(System::block_number().is_zero());
			System::on_created_account(Default::default());
			assert!(System::events().is_empty());
			// Events will be emitted starting on block 1
			System::set_block_number(1);
			System::on_created_account(Default::default());
			assert!(System::events().len() == 1);
		});
	}