// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork use super::*; use crate::fixture::make_submit_delivery_receipt_message; use codec::Encode; use pezframe_benchmarking::v2::*; use pezframe_support::{traits::Hooks, BoundedVec}; use pezframe_system::RawOrigin; use pezsnowbridge_outbound_queue_primitives::v2::{Command, Initializer, Message}; use pezsp_core::{H160, H256}; #[allow(unused_imports)] use crate::Pezpallet as OutboundQueue; #[benchmarks( where ::MaxMessagePayloadSize: Get, ::AccountId: From<[u8; 32]>, )] mod benchmarks { use super::*; use pezframe_support::assert_ok; /// Build `Upgrade` message with `MaxMessagePayloadSize`, in the worst-case. fn build_message() -> (Message, OutboundMessage) { let commands = vec![Command::Upgrade { impl_address: H160::zero(), impl_code_hash: H256::zero(), initializer: Initializer { params: core::iter::repeat_with(|| 1_u8) .take(::MaxMessagePayloadSize::get() as usize) .collect(), maximum_required_gas: 200_000, }, }]; let message = Message { origin: Default::default(), id: H256::default(), fee: 0, commands: BoundedVec::try_from(commands.clone()).unwrap(), }; let wrapped_commands: Vec = commands .into_iter() .map(|command| OutboundCommandWrapper { kind: command.index(), gas: T::GasMeter::maximum_dispatch_gas_used_at_most(&command), payload: command.abi_encode(), }) .collect(); let outbound_message = OutboundMessage { origin: Default::default(), nonce: 1, topic: H256::default(), commands: wrapped_commands.clone().try_into().unwrap(), }; (message, outbound_message) } /// Initialize `MaxMessagesPerBlock` messages need to be committed, in the worst-case. fn initialize_worst_case() { for _ in 0..T::MaxMessagesPerBlock::get() { initialize_with_one_message::(); } } /// Initialize with a single message fn initialize_with_one_message() { let (message, outbound_message) = build_message::(); let leaf = ::Hashing::hash(&message.encode()); MessageLeaves::::append(leaf); Messages::::append(outbound_message); } /// Benchmark for processing a message. #[benchmark] fn do_process_message() -> Result<(), BenchmarkError> { let (enqueued_message, _) = build_message::(); let origin = T::AggregateMessageOrigin::from([1; 32].into()); let message = enqueued_message.encode(); #[block] { let _ = OutboundQueue::::do_process_message(origin, &message).unwrap(); } assert_eq!(MessageLeaves::::decode_len().unwrap(), 1); Ok(()) } /// Benchmark for producing final messages commitment, in the worst-case #[benchmark] fn commit() -> Result<(), BenchmarkError> { initialize_worst_case::(); #[block] { OutboundQueue::::commit(); } Ok(()) } /// Benchmark for producing commitment for a single message, used to estimate the delivery /// cost. The assumption is that cost of commit a single message is even higher than the average /// cost of commit all messages. #[benchmark] fn commit_single() -> Result<(), BenchmarkError> { initialize_with_one_message::(); #[block] { OutboundQueue::::commit(); } Ok(()) } /// Benchmark for `on_initialize` in the worst-case #[benchmark] fn on_initialize() -> Result<(), BenchmarkError> { initialize_worst_case::(); #[block] { OutboundQueue::::on_initialize(1_u32.into()); } Ok(()) } /// Benchmark the entire process flow in the worst-case. This can be used to determine /// appropriate values for the configuration parameters `MaxMessagesPerBlock` and /// `MaxMessagePayloadSize` #[benchmark] fn process() -> Result<(), BenchmarkError> { initialize_worst_case::(); let origin = T::AggregateMessageOrigin::from([1; 32].into()); let (enqueued_message, _) = build_message::(); let message = enqueued_message.encode(); #[block] { OutboundQueue::::on_initialize(1_u32.into()); for _ in 0..T::MaxMessagesPerBlock::get() { OutboundQueue::::do_process_message(origin.clone(), &message).unwrap(); } OutboundQueue::::commit(); } Ok(()) } #[benchmark] fn submit_delivery_receipt() -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let message = make_submit_delivery_receipt_message(); T::Helper::initialize_storage(message.finalized_header, message.block_roots_root); let receipt = DeliveryReceipt::try_from(&message.event.event_log).unwrap(); let order = PendingOrder { nonce: receipt.nonce, fee: 0, block_number: pezframe_system::Pezpallet::::current_block_number(), }; >::insert(receipt.nonce, order); #[block] { assert_ok!(OutboundQueue::::submit_delivery_receipt( RawOrigin::Signed(caller.clone()).into(), Box::new(message.event), )); } Ok(()) } impl_benchmark_test_suite!(OutboundQueue, crate::mock::new_tester(), crate::mock::Test,); }