Exchange pallet benchmarks (#158)

* exchange benchmarks: framework

* updated comment about tx size

Co-authored-by: Tomasz Drwięga <tomasz@parity.io>
This commit is contained in:
Svyatoslav Nikolsky
2020-07-16 12:58:46 +03:00
committed by Bastian Köcher
parent ebdfffc4b1
commit 00bd13f8cd
10 changed files with 281 additions and 45 deletions
@@ -0,0 +1,134 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Exchange module complexity is mostly determined by callbacks, defined by runtime.
//! So we are giving runtime opportunity to prepare environment and construct proof
//! before invoking module calls.
use super::{Blockchain, Call, Module as CurrencyExchangeModule, Trait as CurrencyExchangeTrait};
use sp_std::prelude::*;
use frame_benchmarking::{account, benchmarks};
use frame_system::RawOrigin;
const SEED: u32 = 0;
const WORST_TX_SIZE_FACTOR: u32 = 1000;
const WORST_PROOF_SIZE_FACTOR: u32 = 1000;
/// Module we're benchmarking here.
pub struct Module<T: Trait>(CurrencyExchangeModule<T>);
/// Proof benchmarking parameters.
pub struct ProofParams<Recipient> {
/// Funds recipient.
pub recipient: Recipient,
/// When true, recipient must exists before import.
pub recipient_exists: bool,
/// When 0, transaction should have minimal possible size. When this value has non-zero value n,
/// transaction size should be (if possible) near to MIN_SIZE + n * SIZE_FACTOR.
pub transaction_size_factor: u32,
/// When 0, proof should have minimal possible size. When this value has non-zero value n,
/// proof size should be (if possible) near to MIN_SIZE + n * SIZE_FACTOR.
pub proof_size_factor: u32,
}
/// Trait that must be implemented by runtime.
pub trait Trait: CurrencyExchangeTrait {
/// Prepare proof for importing exchange transaction.
fn make_proof(
proof_params: ProofParams<Self::AccountId>,
) -> <<Self as CurrencyExchangeTrait>::PeerBlockchain as Blockchain>::TransactionInclusionProof;
}
benchmarks! {
_ { }
// Benchmark `import_peer_transaction` extrinsic with the best possible conditions:
// * Proof is the transaction itself.
// * Transaction has minimal size.
// * Recipient account exists.
import_peer_transaction_best_case {
let i in 1..100;
let recipient: T::AccountId = account("recipient", i, SEED);
let proof = T::make_proof(ProofParams {
recipient: recipient.clone(),
recipient_exists: true,
transaction_size_factor: 0,
proof_size_factor: 0,
});
}: import_peer_transaction(RawOrigin::Signed(recipient), proof)
// Benchmark `import_peer_transaction` extrinsic when recipient account does not exists.
import_peer_transaction_when_recipient_does_not_exists {
let i in 1..100;
let recipient: T::AccountId = account("recipient", i, SEED);
let proof = T::make_proof(ProofParams {
recipient: recipient.clone(),
recipient_exists: false,
transaction_size_factor: 0,
proof_size_factor: 0,
});
}: import_peer_transaction(RawOrigin::Signed(recipient), proof)
// Benchmark `import_peer_transaction` when transaction size increases.
import_peer_transaction_when_transaction_size_increases {
let i in 1..100;
let n in 1..WORST_TX_SIZE_FACTOR;
let recipient: T::AccountId = account("recipient", i, SEED);
let proof = T::make_proof(ProofParams {
recipient: recipient.clone(),
recipient_exists: true,
transaction_size_factor: n,
proof_size_factor: 0,
});
}: import_peer_transaction(RawOrigin::Signed(recipient), proof)
// Benchmark `import_peer_transaction` when proof size increases.
import_peer_transaction_when_proof_size_increases {
let i in 1..100;
let n in 1..WORST_PROOF_SIZE_FACTOR;
let recipient: T::AccountId = account("recipient", i, SEED);
let proof = T::make_proof(ProofParams {
recipient: recipient.clone(),
recipient_exists: true,
transaction_size_factor: 0,
proof_size_factor: n,
});
}: import_peer_transaction(RawOrigin::Signed(recipient), proof)
// Benchmark `import_peer_transaction` extrinsic with the worst possible conditions:
// * Proof is large.
// * Transaction has large size.
// * Recipient account does not exists.
import_peer_transaction_worst_case {
let i in 1..100;
let m in WORST_TX_SIZE_FACTOR..WORST_TX_SIZE_FACTOR+1;
let n in WORST_PROOF_SIZE_FACTOR..WORST_PROOF_SIZE_FACTOR+1;
let recipient: T::AccountId = account("recipient", i, SEED);
let proof = T::make_proof(ProofParams {
recipient: recipient.clone(),
recipient_exists: false,
transaction_size_factor: m,
proof_size_factor: n,
});
}: import_peer_transaction(RawOrigin::Signed(recipient), proof)
}
+6 -3
View File
@@ -24,6 +24,9 @@ use sp_currency_exchange::{
};
use sp_runtime::DispatchResult;
#[cfg(feature = "runtime-benchmarks")]
pub mod benchmarking;
/// Called when transaction is submitted to the exchange module.
pub trait OnTransactionSubmitted<AccountId> {
/// Called when valid transaction is submitted and accepted by the module.
@@ -229,7 +232,7 @@ mod tests {
fn parse(tx: &Self::Transaction) -> sp_currency_exchange::Result<RawTransaction> {
match tx.id {
INVALID_TRANSACTION_ID => Err(sp_currency_exchange::Error::InvalidTransaction),
INVALID_TRANSACTION_ID => Err(ExchangeError::InvalidTransaction),
_ => Ok(tx.clone()),
}
}
@@ -243,7 +246,7 @@ mod tests {
fn map(peer_recipient: Self::PeerRecipient) -> sp_currency_exchange::Result<Self::Recipient> {
match peer_recipient {
UNKNOWN_RECIPIENT_ID => Err(sp_currency_exchange::Error::FailedToMapRecipients),
UNKNOWN_RECIPIENT_ID => Err(ExchangeError::FailedToMapRecipients),
_ => Ok(peer_recipient * 10),
}
}
@@ -257,7 +260,7 @@ mod tests {
fn convert(amount: Self::SourceAmount) -> sp_currency_exchange::Result<Self::TargetAmount> {
match amount {
INVALID_AMOUNT => Err(sp_currency_exchange::Error::FailedToConvertCurrency),
INVALID_AMOUNT => Err(ExchangeError::FailedToConvertCurrency),
_ => Ok(amount * 10),
}
}
@@ -48,7 +48,6 @@ benchmarks! {
header
},
);
}: import_unsigned_header(RawOrigin::None, header, None)
verify {
let storage = BridgeStorage::<T>::new();
+2 -2
View File
@@ -44,7 +44,7 @@ mod benchmarking;
mod mock;
#[cfg(any(feature = "runtime-benchmarks", test))]
mod test_utils;
pub mod test_utils;
/// Maximal number of blocks we're pruning in single import call.
const MAX_BLOCKS_TO_PRUNE_IN_SINGLE_IMPORT: u64 = 8;
@@ -547,7 +547,7 @@ impl<T: Trait> frame_support::unsigned::ValidateUnsigned for Module<T> {
/// Runtime bridge storage.
#[derive(Default)]
struct BridgeStorage<T>(sp_std::marker::PhantomData<T>);
pub struct BridgeStorage<T>(sp_std::marker::PhantomData<T>);
impl<T: Trait> BridgeStorage<T> {
/// Create new BridgeStorage.
+22 -7
View File
@@ -27,7 +27,7 @@
use crate::finality::FinalityVotes;
use crate::validators::CHANGE_EVENT_HASH;
use crate::verification::calculate_score;
use crate::{HeaderToImport, Storage};
use crate::{HeaderToImport, Storage, Trait};
use primitives::{
rlp_encode,
@@ -60,25 +60,34 @@ impl HeaderBuilder {
}
}
/// Creates default header on top of parent with given hash.
/// Creates default header on top of test parent with given hash.
#[cfg(test)]
pub fn with_parent_hash(parent_hash: H256) -> Self {
use crate::mock::TestRuntime;
Self::with_parent_hash_on_runtime::<crate::mock::TestRuntime>(parent_hash)
}
/// Creates default header on top of test parent with given number. First parent is selected.
#[cfg(test)]
pub fn with_parent_number(parent_number: u64) -> Self {
Self::with_parent_number_on_runtime::<crate::mock::TestRuntime>(parent_number)
}
/// Creates default header on top of parent with given hash.
pub fn with_parent_hash_on_runtime<T: Trait>(parent_hash: H256) -> Self {
use crate::Headers;
use frame_support::StorageMap;
let parent_header = Headers::<TestRuntime>::get(&parent_hash).unwrap().header;
let parent_header = Headers::<T>::get(&parent_hash).unwrap().header;
Self::with_parent(&parent_header)
}
/// Creates default header on top of parent with given number. First parent is selected.
#[cfg(test)]
pub fn with_parent_number(parent_number: u64) -> Self {
pub fn with_parent_number_on_runtime<T: Trait>(parent_number: u64) -> Self {
use crate::HeadersByNumber;
use frame_support::StorageMap;
let parent_hash = HeadersByNumber::get(parent_number).unwrap()[0].clone();
Self::with_parent_hash(parent_hash)
Self::with_parent_hash_on_runtime::<T>(parent_hash)
}
/// Creates default header on top of non-existent parent.
@@ -185,6 +194,12 @@ impl HeaderBuilder {
self
}
/// Update transactions root field of this header.
pub fn with_transactions_root(mut self, transactions_root: H256) -> Self {
self.header.transactions_root = transactions_root;
self
}
/// Signs header by given author.
pub fn sign_by(self, author: &SecretKey) -> Header {
self.header.sign_by(author)