#[cfg(feature = "runtime-benchmarks")]
use super::*;
use crate::claims::Call;
use frame_benchmarking::v2::*;
use frame_support::{
dispatch::{DispatchInfo, GetDispatchInfo},
traits::UnfilteredDispatchable,
};
use frame_system::RawOrigin;
use secp_utils::*;
use sp_runtime::{
traits::{DispatchTransaction, ValidateUnsigned},
DispatchResult,
};
const SEED: u32 = 0;
const MAX_CLAIMS: u32 = 10_000;
const VALUE: u32 = 1_000_000;
fn create_claim<T: Config>(input: u32) -> DispatchResult {
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap();
let eth_address = eth(&secret_key);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
None,
)?;
Ok(())
}
fn create_claim_attest<T: Config>(input: u32) -> DispatchResult {
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap();
let eth_address = eth(&secret_key);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
Some(Default::default()),
)?;
Ok(())
}
#[benchmarks(
where
<T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>> + From<Call<T>>,
<T as frame_system::Config>::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
<<T as frame_system::Config>::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + AsTransactionAuthorizedOrigin + Clone,
<<T as frame_system::Config>::RuntimeCall as Dispatchable>::PostInfo: Default,
)]
mod benchmarks {
use super::*;
#[benchmark]
fn claim() -> Result<(), BenchmarkError> {
let c = MAX_CLAIMS;
for _ in 0..c / 2 {
create_claim::<T>(c)?;
create_claim_attest::<T>(u32::MAX - c)?;
}
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&c.encode())).unwrap();
let eth_address = eth(&secret_key);
let account: T::AccountId = account("user", c, SEED);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
let signature = sig::<T>(&secret_key, &account.encode(), &[][..]);
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
None,
)?;
assert_eq!(Claims::<T>::get(eth_address), Some(VALUE.into()));
let source = sp_runtime::transaction_validity::TransactionSource::External;
let call_enc =
Call::<T>::claim { dest: account.clone(), ethereum_signature: signature.clone() }
.encode();
#[block]
{
let call = <Call<T> as Decode>::decode(&mut &*call_enc)
.expect("call is encoded above, encoding must be correct");
super::Pallet::<T>::validate_unsigned(source, &call)
.map_err(|e| -> &'static str { e.into() })?;
call.dispatch_bypass_filter(RawOrigin::None.into())?;
}
assert_eq!(Claims::<T>::get(eth_address), None);
Ok(())
}
#[benchmark]
fn mint_claim() -> Result<(), BenchmarkError> {
let c = MAX_CLAIMS;
for _ in 0..c / 2 {
create_claim::<T>(c)?;
create_claim_attest::<T>(u32::MAX - c)?;
}
let eth_address = account("eth_address", 0, SEED);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
let statement = StatementKind::Regular;
#[extrinsic_call]
_(RawOrigin::Root, eth_address, VALUE.into(), vesting, Some(statement));
assert_eq!(Claims::<T>::get(eth_address), Some(VALUE.into()));
Ok(())
}
#[benchmark]
fn claim_attest() -> Result<(), BenchmarkError> {
let c = MAX_CLAIMS;
for _ in 0..c / 2 {
create_claim::<T>(c)?;
create_claim_attest::<T>(u32::MAX - c)?;
}
let attest_c = u32::MAX - c;
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
let eth_address = eth(&secret_key);
let account: T::AccountId = account("user", c, SEED);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
let statement = StatementKind::Regular;
let signature = sig::<T>(&secret_key, &account.encode(), statement.to_text());
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
Some(statement),
)?;
assert_eq!(Claims::<T>::get(eth_address), Some(VALUE.into()));
let call_enc = Call::<T>::claim_attest {
dest: account.clone(),
ethereum_signature: signature.clone(),
statement: StatementKind::Regular.to_text().to_vec(),
}
.encode();
let source = sp_runtime::transaction_validity::TransactionSource::External;
#[block]
{
let call = <Call<T> as Decode>::decode(&mut &*call_enc)
.expect("call is encoded above, encoding must be correct");
super::Pallet::<T>::validate_unsigned(source, &call)
.map_err(|e| -> &'static str { e.into() })?;
call.dispatch_bypass_filter(RawOrigin::None.into())?;
}
assert_eq!(Claims::<T>::get(eth_address), None);
Ok(())
}
#[benchmark]
fn attest() -> Result<(), BenchmarkError> {
let c = MAX_CLAIMS;
for _ in 0..c / 2 {
create_claim::<T>(c)?;
create_claim_attest::<T>(u32::MAX - c)?;
}
let attest_c = u32::MAX - c;
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
let eth_address = eth(&secret_key);
let account: T::AccountId = account("user", c, SEED);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
let statement = StatementKind::Regular;
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
Some(statement),
)?;
Preclaims::<T>::insert(&account, eth_address);
assert_eq!(Claims::<T>::get(eth_address), Some(VALUE.into()));
let stmt = StatementKind::Regular.to_text().to_vec();
#[extrinsic_call]
_(RawOrigin::Signed(account), stmt);
assert_eq!(Claims::<T>::get(eth_address), None);
Ok(())
}
#[benchmark]
fn move_claim() -> Result<(), BenchmarkError> {
let c = MAX_CLAIMS;
for _ in 0..c / 2 {
create_claim::<T>(c)?;
create_claim_attest::<T>(u32::MAX - c)?;
}
let attest_c = u32::MAX - c;
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
let eth_address = eth(&secret_key);
let new_secret_key =
libsecp256k1::SecretKey::parse(&keccak_256(&(u32::MAX / 2).encode())).unwrap();
let new_eth_address = eth(&new_secret_key);
let account: T::AccountId = account("user", c, SEED);
Preclaims::<T>::insert(&account, eth_address);
assert!(Claims::<T>::contains_key(eth_address));
assert!(!Claims::<T>::contains_key(new_eth_address));
#[extrinsic_call]
_(RawOrigin::Root, eth_address, new_eth_address, Some(account));
assert!(!Claims::<T>::contains_key(eth_address));
assert!(Claims::<T>::contains_key(new_eth_address));
Ok(())
}
#[benchmark(extra)]
fn keccak256(i: Linear<0, 10_000>) {
let bytes = (i).encode();
#[block]
{
for _ in 0..i {
let _hash = keccak_256(&bytes);
}
}
}
#[benchmark(extra)]
fn eth_recover(i: Linear<0, 1_000>) {
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&i.encode())).unwrap();
let account: T::AccountId = account("user", i, SEED);
let signature = sig::<T>(&secret_key, &account.encode(), &[][..]);
let data = account.using_encoded(to_ascii_hex);
let extra = StatementKind::default().to_text();
#[block]
{
for _ in 0..i {
assert!(super::Pallet::<T>::eth_recover(&signature, &data, extra).is_some());
}
}
}
#[benchmark]
fn prevalidate_attests() -> Result<(), BenchmarkError> {
let c = MAX_CLAIMS;
for _ in 0..c / 2 {
create_claim::<T>(c)?;
create_claim_attest::<T>(u32::MAX - c)?;
}
let ext = PrevalidateAttests::<T>::new();
let call = super::Call::attest { statement: StatementKind::Regular.to_text().to_vec() };
let call: <T as frame_system::Config>::RuntimeCall = call.into();
let info = call.get_dispatch_info();
let attest_c = u32::MAX - c;
let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
let eth_address = eth(&secret_key);
let account: T::AccountId = account("user", c, SEED);
let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
let statement = StatementKind::Regular;
super::Pallet::<T>::mint_claim(
RawOrigin::Root.into(),
eth_address,
VALUE.into(),
vesting,
Some(statement),
)?;
Preclaims::<T>::insert(&account, eth_address);
assert_eq!(Claims::<T>::get(eth_address), Some(VALUE.into()));
#[block]
{
assert!(ext
.test_run(RawOrigin::Signed(account).into(), &call, &info, 0, 0, |_| {
Ok(Default::default())
})
.unwrap()
.is_ok());
}
Ok(())
}
impl_benchmark_test_suite!(
Pallet,
crate::claims::mock::new_test_ext(),
crate::claims::mock::Test,
);
}