-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
Add the multi-batching pallet (#7)
* Add multi-batching pallet * Reject replays, emit events * Fix missing runtime event assoc type * Implement the new interface * Include testing to validate that batch() works * Remove scaffolding, add more tests * Benchmarks, cleanup * Improve benchmarks, add weights * Add README.md, improve docs * Implement review fixes, expiry * Re-generate weights --------- Co-authored-by: José Molina <[email protected]> Co-authored-by: Valentin Fernandez <[email protected]>
- v1.17.0
- v1.17.0-rc6
- v1.17.0-rc5
- v1.17.0-rc4
- v1.17.0-rc3
- v1.17.0-rc2
- v1.17.0-rc1
- v1.16.3
- v1.15.6
- v1.15.6-rc2
- v1.15.6-rc1
- v1.15.5
- v1.15.4
- v1.15.4-remove-migration
- v1.15.4-paseo-migration
- v1.15.4-1
- v1.15.3
- v1.15.3-rc2
- v1.15.3-rc1
- v1.15.3-no-full-pov-size
- v1.13.9-rc1
- v1.13.8-rc1
- v1.13.7
- v1.13.6
- v1.13.5
- v1.13.4
- v1.13.3
- v1.13.2
- v1.13.1
- v1.13.0
- v1.11.4
- v1.11.3
- v1.11.2
- v1.11.2-mythical-private-testnet-1009
- v1.11.1
- v1.11.0-westend
- v1.8.3-mythical-private-testnet-1008
- v1.8.3-mythical-private-testnet-1007
- v1.8.3-mythical-private-testnet
- no-custom-pool
- 1.13.3
1 parent
e85ed1b
commit 71e5c8e
Showing
16 changed files
with
1,547 additions
and
6 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
[package] | ||
name = "pallet-multibatching" | ||
version = "1.1.0-dev" | ||
description = "Off-line multisignature atomic batching" | ||
authors = ["Mykola Samardak <[email protected]>"] | ||
edition = "2021" | ||
license = "MIT-0" | ||
publish = false | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] | ||
|
||
[dependencies] | ||
parity-scale-codec = { workspace = true, default-features = false, features = [ | ||
"derive", | ||
] } | ||
scale-info = { workspace = true, default-features = false, features = [ | ||
"derive", | ||
] } | ||
frame-benchmarking = { workspace = true, default-features = false, optional = true } | ||
frame-support = { workspace = true } | ||
frame-system = { workspace = true } | ||
sp-std = { workspace = true, default-features = false } | ||
sp-core = { workspace = true, default-features = false } | ||
pallet-timestamp = { workspace = true, default-features = false } | ||
|
||
# benchmarking dependencies | ||
account = { workspace = true, optional = true } | ||
sp-io = { workspace = true, default-features = false, optional = true } | ||
|
||
[dev-dependencies] | ||
sp-runtime = { workspace = true, default-features = false } | ||
account = { workspace = true } | ||
sp-core = { workspace = true, default-features = false } | ||
sp-io = { workspace = true, default-features = false } | ||
sp-keystore = { workspace = true } | ||
|
||
[features] | ||
default = ["std"] | ||
std = [ | ||
"parity-scale-codec/std", | ||
"frame-benchmarking?/std", | ||
"frame-support/std", | ||
"frame-system/std", | ||
"scale-info/std", | ||
"sp-std/std", | ||
"account?/std", | ||
"sp-io?/std", | ||
] | ||
runtime-benchmarks = [ | ||
"frame-benchmarking/runtime-benchmarks", | ||
"account", | ||
"sp-io", | ||
] | ||
try-runtime = ["frame-support/try-runtime"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Multibatching pallet | ||
|
||
An alternative to standard batching utilities. | ||
|
||
## Overview | ||
|
||
The Multibatching pallet allows for an alternative approach to batching: | ||
calls in a Multibatching batch can be made by multiple users, and their | ||
approvals are collected off-chain. See docs for `batch()` for detailed | ||
description. | ||
|
||
## Dispatchable functions | ||
|
||
- `batch()`: The batching function, allows making multiple calls by | ||
multiple users in a single transaction. | ||
- `force_set_domain()`: Sets the domain for this specific pallet instance. | ||
Domain is a part of data that has to be signed by each caller in a batch, | ||
and is there to protect the users from replay attacks across networks. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#![cfg(feature = "runtime-benchmarks")] | ||
use super::*; | ||
#[allow(unused_imports)] | ||
use crate::Pallet as Multibatching; | ||
use frame_benchmarking::v2::*; | ||
use frame_support::{dispatch::RawOrigin, BoundedVec}; | ||
use sp_core::ecdsa::Public; | ||
use sp_io::{ | ||
crypto::{ecdsa_generate, ecdsa_sign_prehashed}, | ||
hashing::keccak_256, | ||
}; | ||
use sp_std::vec::Vec; | ||
|
||
impl<Moment> BenchmarkHelper<Moment> for () | ||
where | ||
Moment: From<u64>, | ||
{ | ||
fn timestamp(value: u64) -> Moment { | ||
value.into() | ||
} | ||
} | ||
|
||
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) { | ||
frame_system::Pallet::<T>::assert_last_event(generic_event.into()); | ||
} | ||
|
||
#[benchmarks( | ||
where | ||
T::Signer: From<EthereumSigner>, | ||
T::Signature: From<EthereumSignature>, | ||
T::Hash: From<[u8;32]>, | ||
T::Hash: Into<[u8;32]>, | ||
<T as Config>::RuntimeCall: From<Call<T>>, | ||
<T as frame_system::Config>::AccountId: From<AccountId20>, | ||
<T as frame_system::Config>::RuntimeEvent: From<Event<T>>, | ||
<T as frame_system::Config>::RuntimeOrigin: From<frame_system::RawOrigin<AccountId20>>, | ||
)] | ||
pub mod benchmarks { | ||
use super::*; | ||
use account::{AccountId20, EthereumSignature, EthereumSigner}; | ||
use frame_support::sp_runtime::traits::IdentifyAccount; | ||
use parity_scale_codec::Encode; | ||
|
||
use pallet_timestamp::Pallet as Timestamp; | ||
|
||
#[benchmark] | ||
fn batch(c: Linear<1, 1000>, s: Linear<1, 10>) { | ||
let call_count = c as usize; | ||
let signer_count = s as usize; | ||
|
||
let domain: [u8; 32] = *b".myth.pallet-multibatching.bench"; | ||
let bias = [0u8; 32]; | ||
let expires_at = Timestamp::<T>::get() + T::BenchmarkHelper::timestamp(100_000); | ||
|
||
let sender: AccountId20 = whitelisted_caller(); | ||
|
||
let mut signers = Vec::<(Public, EthereumSigner, AccountId20)>::with_capacity(signer_count); | ||
for _ in 0..signer_count { | ||
let public: Public = ecdsa_generate(0.into(), None); | ||
let signer: EthereumSigner = public.into(); | ||
let account = signer.clone().into_account(); | ||
signers.push((public, signer, account)); | ||
} | ||
|
||
let mut calls = BoundedVec::new(); | ||
let iter = (0..call_count).zip(signers.iter().cycle()); | ||
for (_, (_, signer, _)) in iter { | ||
let call = frame_system::Call::remark { remark: Default::default() }.into(); | ||
calls | ||
.try_push(BatchedCall::<T> { from: signer.clone().into(), call }) | ||
.expect("Benchmark config must match runtime config for BoundedVec size"); | ||
} | ||
|
||
let pseudo_call: <T as Config>::RuntimeCall = Call::<T>::batch { | ||
domain, | ||
sender: sender.into(), | ||
bias, | ||
expires_at, | ||
calls: calls.clone(), | ||
approvals: BoundedVec::new(), | ||
} | ||
.into(); | ||
let pseudo_call_bytes = pseudo_call.encode(); | ||
let hash = keccak_256(&pseudo_call_bytes); | ||
|
||
let mut approvals = BoundedVec::new(); | ||
for (public, _signer, account) in &signers { | ||
approvals | ||
.try_push(Approval::<T> { | ||
from: EthereumSigner::from(account.0).into(), | ||
signature: EthereumSignature::from( | ||
ecdsa_sign_prehashed(0.into(), public, &hash).unwrap(), | ||
) | ||
.into(), | ||
}) | ||
.expect("Benchmark config must match runtime config for BoundedVec size"); | ||
} | ||
approvals.sort_by_key(|a| a.from.clone()); | ||
|
||
Pallet::<T>::force_set_domain(RawOrigin::Root.into(), domain) | ||
.expect("force_set_domain must succeed"); | ||
|
||
#[extrinsic_call] | ||
_(RawOrigin::Signed(sender), domain, sender.into(), bias, expires_at, calls, approvals); | ||
} | ||
|
||
#[benchmark] | ||
fn force_set_domain() { | ||
let domain = [0; 32]; | ||
|
||
#[extrinsic_call] | ||
_(RawOrigin::Root, domain); | ||
|
||
assert_last_event::<T>(Event::DomainSet { domain }.into()); | ||
} | ||
|
||
impl_benchmark_test_suite!(Multibatching, crate::mock::new_test_ext(), crate::mock::Test); | ||
} |
Oops, something went wrong.