From f5314b2b782a17305834b447233c61dae8515ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=CC=81=20Molina?= Date: Tue, 24 Sep 2024 18:40:15 +0200 Subject: [PATCH 01/10] Remove testnet migrations --- runtime/testnet/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/runtime/testnet/src/lib.rs b/runtime/testnet/src/lib.rs index 2870fd7..0d8670b 100644 --- a/runtime/testnet/src/lib.rs +++ b/runtime/testnet/src/lib.rs @@ -119,6 +119,9 @@ impl frame_support::traits::OnRuntimeUpgrade for PrepareForMove { } } +/// Pending migrations to be applied. +pub type Migrations = (); + /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -126,11 +129,7 @@ pub type Executive = frame_executive::Executive< frame_system::ChainContext, Runtime, AllPalletsWithSystem, - ( - pallet_collator_selection::migration::v2::MigrationToV2, - cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, - PrepareForMove, - ), + Migrations, >; // TODO remove this when the migration is completed From 9f394f45d5a3c7f6c721c93bbd25fce758d54185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=CC=81=20Molina?= Date: Tue, 24 Sep 2024 19:39:09 +0200 Subject: [PATCH 02/10] Remove migration implementation --- runtime/mainnet/src/lib.rs | 5 ----- runtime/testnet/src/lib.rs | 5 ----- 2 files changed, 10 deletions(-) diff --git a/runtime/mainnet/src/lib.rs b/runtime/mainnet/src/lib.rs index f397bb0..ef81e41 100644 --- a/runtime/mainnet/src/lib.rs +++ b/runtime/mainnet/src/lib.rs @@ -114,11 +114,6 @@ pub type Executive = frame_executive::Executive< (), >; -// TODO remove this when the migration is completed -impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { - type ChannelList = ParachainSystem; -} - pub mod fee { use super::{Balance, ExtrinsicBaseWeight, MILLI_DOT, MILLI_MYTH}; use frame_support::weights::{ diff --git a/runtime/testnet/src/lib.rs b/runtime/testnet/src/lib.rs index 0d8670b..fbdc88d 100644 --- a/runtime/testnet/src/lib.rs +++ b/runtime/testnet/src/lib.rs @@ -132,11 +132,6 @@ pub type Executive = frame_executive::Executive< Migrations, >; -// TODO remove this when the migration is completed -impl cumulus_pallet_xcmp_queue::migration::v5::V5Config for Runtime { - type ChannelList = ParachainSystem; -} - pub mod fee { use super::{Balance, ExtrinsicBaseWeight, MILLI_MUSE, MILLI_ROC}; use frame_support::weights::{ From 2a4710cfa7f80db989b6313b75002d1bcdbb66c6 Mon Sep 17 00:00:00 2001 From: metricaez Date: Thu, 26 Sep 2024 14:15:09 -0300 Subject: [PATCH 03/10] choir: bump spec ver --- runtime/testnet/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/testnet/src/lib.rs b/runtime/testnet/src/lib.rs index fbdc88d..1fecabf 100644 --- a/runtime/testnet/src/lib.rs +++ b/runtime/testnet/src/lib.rs @@ -244,7 +244,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("muse"), impl_name: create_runtime_str!("muse"), authoring_version: 1, - spec_version: 1017, + spec_version: 1018, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From fb3014bcc838f5ccad7832a0eeb2cfffb052c34f Mon Sep 17 00:00:00 2001 From: Valentin Fernandez Date: Tue, 29 Oct 2024 12:53:49 -0300 Subject: [PATCH 04/10] Remove migration pallet --- Cargo.lock | 24 ------ Cargo.toml | 1 - runtime/mainnet/Cargo.toml | 1 - runtime/testnet/Cargo.toml | 4 - runtime/testnet/src/lib.rs | 11 --- runtime/testnet/src/weights/mod.rs | 1 - .../testnet/src/weights/pallet_migration.rs | 82 ------------------- 7 files changed, 124 deletions(-) delete mode 100644 runtime/testnet/src/weights/pallet_migration.rs diff --git a/Cargo.lock b/Cargo.lock index 10d0f53..4cde9e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5407,7 +5407,6 @@ dependencies = [ "pallet-escrow", "pallet-marketplace", "pallet-message-queue", - "pallet-migration", "pallet-multibatching", "pallet-multisig", "pallet-myth-proxy", @@ -6921,28 +6920,6 @@ dependencies = [ "sp-weights", ] -[[package]] -name = "pallet-migration" -version = "0.0.1" -dependencies = [ - "account", - "frame-benchmarking", - "frame-support", - "frame-system", - "log", - "pallet-balances", - "pallet-dmarket", - "pallet-nfts", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-mmr" version = "37.0.0" @@ -13386,7 +13363,6 @@ dependencies = [ "pallet-escrow", "pallet-marketplace", "pallet-message-queue", - "pallet-migration", "pallet-multibatching", "pallet-multisig", "pallet-myth-proxy", diff --git a/Cargo.toml b/Cargo.toml index dbbdad7..d79fa0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,6 @@ testnet-runtime = { path = "runtime/testnet" } mainnet-runtime = { path = "runtime/mainnet" } pallet-dmarket = { path = "pallets/dmarket", default-features = false } pallet-marketplace = { path = "pallets/marketplace", default-features = false } -pallet-migration = { path = "pallets/migration", default-features = false } pallet-multibatching = { path = "pallets/multibatching", default-features = false } runtime-common = { path = "runtime/common", default-features = false } pallet-escrow = { path = "pallets/escrow", default-features = false } diff --git a/runtime/mainnet/Cargo.toml b/runtime/mainnet/Cargo.toml index b67aee9..2c7cc36 100644 --- a/runtime/mainnet/Cargo.toml +++ b/runtime/mainnet/Cargo.toml @@ -29,7 +29,6 @@ smallvec = { workspace = true } runtime-common = { workspace = true, default-features = false } pallet-dmarket = { workspace = true, default-features = false } pallet-marketplace = { workspace = true, default-features = false } -pallet-migration = { workspace = true, default-features = false } xcm-primitives = { path = "../../primitives/xcm", default-features = false } pallet-escrow = {workspace = true, default-features = false} diff --git a/runtime/testnet/Cargo.toml b/runtime/testnet/Cargo.toml index 12c5330..a141ae1 100644 --- a/runtime/testnet/Cargo.toml +++ b/runtime/testnet/Cargo.toml @@ -25,7 +25,6 @@ smallvec = { workspace = true } runtime-common = { workspace = true, default-features = false } pallet-dmarket = { workspace = true, default-features = false } pallet-marketplace = { workspace = true, default-features = false } -pallet-migration = { workspace = true, default-features = false } pallet-multibatching = { workspace = true, default-features = false } xcm-primitives = { path = "../../primitives/xcm", default-features = false } pallet-escrow = { workspace = true, default-features = false } @@ -124,7 +123,6 @@ std = [ "pallet-dmarket/std", "pallet-multibatching/std", "pallet-marketplace/std", - "pallet-migration/std", "pallet-multisig/std", "pallet-nfts/std", "pallet-session/std", @@ -175,7 +173,6 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-dmarket/runtime-benchmarks", "pallet-marketplace/runtime-benchmarks", - "pallet-migration/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-multibatching/runtime-benchmarks", "pallet-nfts/runtime-benchmarks", @@ -212,7 +209,6 @@ try-runtime = [ "pallet-dmarket/try-runtime", "pallet-multibatching/try-runtime", "pallet-marketplace/try-runtime", - "pallet-migration/try-runtime", "pallet-multisig/try-runtime", "pallet-nfts/try-runtime", "pallet-session/try-runtime", diff --git a/runtime/testnet/src/lib.rs b/runtime/testnet/src/lib.rs index 1fecabf..6e45f0f 100644 --- a/runtime/testnet/src/lib.rs +++ b/runtime/testnet/src/lib.rs @@ -695,15 +695,6 @@ impl pallet_dmarket::Config for Runtime { type BenchmarkHelper = (); } -impl pallet_migration::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type Currency = Balances; - type WeightInfo = weights::pallet_migration::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - parameter_types! { pub const ProxyDepositBase: Balance = deposit(1, 8); pub const ProxyDepositFactor: Balance = deposit(0, 33); @@ -897,7 +888,6 @@ construct_runtime!( // Other pallets Proxy: pallet_proxy = 40, Vesting: pallet_vesting = 41, - Migration: pallet_migration = 42, Escrow: pallet_escrow = 50, MythProxy: pallet_myth_proxy = 51, @@ -973,7 +963,6 @@ mod benches { [pallet_collator_selection, CollatorSelection] [pallet_nfts, Nfts] [pallet_marketplace, Marketplace] - [pallet_migration, Migration] [pallet_proxy, Proxy] [pallet_escrow, Escrow] [pallet_vesting, Vesting] diff --git a/runtime/testnet/src/weights/mod.rs b/runtime/testnet/src/weights/mod.rs index 538d296..b80dbd3 100644 --- a/runtime/testnet/src/weights/mod.rs +++ b/runtime/testnet/src/weights/mod.rs @@ -37,7 +37,6 @@ pub mod pallet_dmarket; pub mod pallet_escrow; pub mod pallet_marketplace; pub mod pallet_message_queue; -pub mod pallet_migration; pub mod pallet_multibatching; pub mod pallet_multisig; pub mod pallet_myth_proxy; diff --git a/runtime/testnet/src/weights/pallet_migration.rs b/runtime/testnet/src/weights/pallet_migration.rs deleted file mode 100644 index 44bbdf4..0000000 --- a/runtime/testnet/src/weights/pallet_migration.rs +++ /dev/null @@ -1,82 +0,0 @@ - -//! Autogenerated weights for `pallet_migration` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 42.0.0 -//! DATE: 2024-09-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `blockdeep-ref-hw`, CPU: `AMD EPYC 7232P 8-Core Processor` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("local-v")`, DB CACHE: 1024 - -// Executed Command: -// ./target/release/mythos-node -// benchmark -// pallet -// --chain -// local-v -// --pallet -// pallet_migration -// --extrinsic -// * -// --wasm-execution -// compiled -// --steps -// 50 -// --repeat -// 20 -// --output -// ./runtime/testnet/src/weights/pallet_migration.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions for `pallet_migration`. -pub struct WeightInfo(PhantomData); -impl pallet_migration::WeightInfo for WeightInfo { - /// Storage: `Migration::Migrator` (r:1 w:1) - /// Proof: `Migration::Migrator` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) - fn force_set_migrator() -> Weight { - // Proof Size summary in bytes: - // Measured: `3` - // Estimated: `1505` - // Minimum execution time: 11_090_000 picoseconds. - Weight::from_parts(11_620_000, 0) - .saturating_add(Weight::from_parts(0, 1505)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Migration::Migrator` (r:1 w:0) - /// Proof: `Migration::Migrator` (`max_values`: Some(1), `max_size`: Some(20), added: 515, mode: `MaxEncodedLen`) - /// Storage: `Dmarket::DmarketCollection` (r:1 w:0) - /// Proof: `Dmarket::DmarketCollection` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Item` (r:1 w:1) - /// Proof: `Nfts::Item` (`max_values`: None, `max_size`: Some(637), added: 3112, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Collection` (r:1 w:0) - /// Proof: `Nfts::Collection` (`max_values`: None, `max_size`: Some(169), added: 2644, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Attribute` (r:1 w:0) - /// Proof: `Nfts::Attribute` (`max_values`: None, `max_size`: Some(495), added: 2970, mode: `MaxEncodedLen`) - /// Storage: `Nfts::CollectionConfigOf` (r:1 w:0) - /// Proof: `Nfts::CollectionConfigOf` (`max_values`: None, `max_size`: Some(142), added: 2617, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemConfigOf` (r:1 w:0) - /// Proof: `Nfts::ItemConfigOf` (`max_values`: None, `max_size`: Some(88), added: 2563, mode: `MaxEncodedLen`) - /// Storage: `Nfts::Account` (r:0 w:2) - /// Proof: `Nfts::Account` (`max_values`: None, `max_size`: Some(116), added: 2591, mode: `MaxEncodedLen`) - /// Storage: `Nfts::ItemPriceOf` (r:0 w:1) - /// Proof: `Nfts::ItemPriceOf` (`max_values`: None, `max_size`: Some(117), added: 2592, mode: `MaxEncodedLen`) - /// Storage: `Nfts::PendingSwapOf` (r:0 w:1) - /// Proof: `Nfts::PendingSwapOf` (`max_values`: None, `max_size`: Some(151), added: 2626, mode: `MaxEncodedLen`) - fn set_item_owner() -> Weight { - // Proof Size summary in bytes: - // Measured: `900` - // Estimated: `4102` - // Minimum execution time: 84_091_000 picoseconds. - Weight::from_parts(85_470_000, 0) - .saturating_add(Weight::from_parts(0, 4102)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(5)) - } -} From a3e1e3e12140dcbf802cc0545067bd314f14ace9 Mon Sep 17 00:00:00 2001 From: Valentin Fernandez Date: Tue, 29 Oct 2024 12:54:31 -0300 Subject: [PATCH 05/10] Increase spec_version --- runtime/testnet/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/testnet/src/lib.rs b/runtime/testnet/src/lib.rs index 6e45f0f..a4c6259 100644 --- a/runtime/testnet/src/lib.rs +++ b/runtime/testnet/src/lib.rs @@ -244,7 +244,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("muse"), impl_name: create_runtime_str!("muse"), authoring_version: 1, - spec_version: 1018, + spec_version: 1019, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, From ab330895b528399aaf2a97cffe1286e235a2e3bc Mon Sep 17 00:00:00 2001 From: Ilya Sinyakin Date: Mon, 21 Oct 2024 14:18:24 +0100 Subject: [PATCH 06/10] feat: multibatching batch v2 was implemented --- pallets/multibatching/README.md | 6 +- pallets/multibatching/src/lib.rs | 131 ++++ pallets/multibatching/src/tests.rs | 623 ++++++++++++++++++ pallets/multibatching/src/weights.rs | 45 ++ .../src/weights/pallet_multibatching.rs | 21 + .../src/weights/pallet_multibatching.rs | 21 + 6 files changed, 845 insertions(+), 2 deletions(-) diff --git a/pallets/multibatching/README.md b/pallets/multibatching/README.md index 166aaa9..18ac810 100644 --- a/pallets/multibatching/README.md +++ b/pallets/multibatching/README.md @@ -6,10 +6,12 @@ An alternative to standard batching utilities. 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. +approvals are collected off-chain. See docs for `batch()` and `batch_v2()` +for detailed description. ## Dispatchable functions - `batch()`: The batching function, allows making multiple calls by multiple users in a single transaction. +- `batch_v2()`: The batching function, allows making multiple calls by + multiple users in a single transaction. diff --git a/pallets/multibatching/src/lib.rs b/pallets/multibatching/src/lib.rs index a37c372..d344c7b 100644 --- a/pallets/multibatching/src/lib.rs +++ b/pallets/multibatching/src/lib.rs @@ -314,6 +314,137 @@ pub mod pallet { ::WeightInfo::batch(calls_len as u32, approvals.len() as u32); Ok(Some(base_weight.saturating_add(weight)).into()) } + + /// Execute multiple calls from multiple callers in a single batch. + /// + /// If one of the calls fails, the whole batch reverts. + /// + /// This function works the same as [Pallet::batch], but the bytes signed by + /// approvers must be wrapped in between ... . + /// This is how the rawSign is currently implemented in modern substrate clients. + /// + #[pallet::call_index(1)] + #[pallet::weight({ + let dispatch_infos = calls.iter().map(|call| call.call.get_dispatch_info()).collect::>(); + let dispatch_weight = dispatch_infos.iter() + .map(|di| di.weight) + .fold(Weight::zero(), |total: Weight, weight: Weight| total.saturating_add(weight)) + .saturating_add(::WeightInfo::batch_v2(calls.len() as u32, approvals.len() as u32)); + let dispatch_class = { + let all_operational = dispatch_infos.iter() + .map(|di| di.class) + .all(|class| class == DispatchClass::Operational); + if all_operational { + DispatchClass::Operational + } else { + DispatchClass::Normal + } + }; + (dispatch_weight, dispatch_class) + })] + pub fn batch_v2( + origin: OriginFor, + domain: [u8; 8], + sender: ::AccountId, + bias: [u8; 32], + expires_at: ::Moment, + calls: BoundedVec, ::MaxCalls>, + approvals: BoundedVec, ::MaxCalls>, + ) -> DispatchResultWithPostInfo { + if calls.is_empty() { + return Err(Error::::NoCalls.into()); + } + if approvals.is_empty() { + return Err(Error::::NoApprovals.into()); + } + + if approvals.len() > 1 { + for pair in approvals.windows(2) { + match pair { + [a, b] if a.from < b.from => (), + _ => return Err(Error::::UnsortedApprovals.into()), + }; + } + } + + // Origin must be `sender`. + match ensure_signed(origin) { + Ok(account_id) if account_id == sender => account_id, + Ok(_) => return Err(Error::::BatchSenderIsNotOrigin.into()), + Err(e) => return Err(e.into()), + }; + + if pallet_timestamp::Pallet::::get() > expires_at { + return Err(Error::::Expired.into()); + } + + ensure!(domain == ::Domain::get(), Error::::InvalidDomain); + + let bytes = Batch { + pallet_index: Self::index() as u8, + call_index: 0, + domain, + sender: sender.clone(), + bias, + expires_at, + calls: calls.clone(), + approvals_zero: 0, + } + .encode(); + let bytes = [b"", &bytes[..], b""].concat(); + let hash = <::Hashing>::hash(&bytes); + + if Applied::::contains_key(hash) { + return Err(Error::::AlreadyApplied.into()); + } + + Applied::::insert(hash, ()); + + // Check the signatures. + for (i, approval) in approvals.iter().enumerate() { + let ok = approval + .signature + .verify(bytes.as_ref(), &approval.from.clone().into_account()); + if !ok { + return Err(Error::::InvalidSignature(i as u16).into()); + } + } + + let mut weight = Weight::zero(); + + let calls_len = calls.len(); + + // Apply calls. + for (i, payload) in calls.into_iter().enumerate() { + let ok = approvals.binary_search_by_key(&&payload.from, |a| &a.from).is_ok(); + if !ok { + return Err(Error::::InvalidCallOrigin(i as u16).into()); + } + + let info = payload.call.get_dispatch_info(); + let origin = <::RuntimeOrigin>::from( + frame_system::RawOrigin::Signed(payload.from.into_account()), + ); + let result = payload.call.dispatch(origin); + weight = weight.saturating_add(extract_actual_weight(&result, &info)); + result.map_err(|mut err| { + // Take the weight of this function itself into account. + let base_weight = ::WeightInfo::batch( + i.saturating_add(1) as u32, + approvals.len() as u32, + ); + // Return the actual used weight + base_weight of this call. + err.post_info = Some(base_weight + weight).into(); + err + })?; + } + + Self::deposit_event(Event::BatchApplied { hash }); + + let base_weight = + ::WeightInfo::batch(calls_len as u32, approvals.len() as u32); + Ok(Some(base_weight.saturating_add(weight)).into()) + } } } diff --git a/pallets/multibatching/src/tests.rs b/pallets/multibatching/src/tests.rs index 46062fe..b8c5e16 100644 --- a/pallets/multibatching/src/tests.rs +++ b/pallets/multibatching/src/tests.rs @@ -628,4 +628,627 @@ mod multibatching_test { ); }) } + + #[test] + fn multibatching_batch_v2_should_work() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = Timestamp::get().saturating_add( + ::Moment::from(1_000_000_000_u64), + ); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + approvals.sort_by_key(|a| a.from.clone()); + + assert_ok!(Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + )); + }) + } + + #[test] + fn multibatching_batch_v2_fails_with_wrong_hashing() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = blake2_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + approvals.sort_by_key(|a| a.from.clone()); + + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::InvalidSignature(0) + ); + }) + } + + #[test] + fn multibatching_batch_v2_fails_with_no_signatures() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let _hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let approvals = BoundedVec::new(); + + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::NoApprovals + ); + }) + } + + #[test] + fn multibatching_batch_v2_fails_if_already_applied() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + approvals.sort_by_key(|a| a.from.clone()); + + assert_ok!(Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls.clone(), + approvals.clone(), + )); + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::AlreadyApplied + ); + }) + } + + #[test] + fn multibatching_batch_v2_should_fail_if_toplevel_signer_is_not_origin() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let wrong_sender = account(1); + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: wrong_sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + approvals.sort_by_key(|a| a.from.clone()); + + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + wrong_sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::BatchSenderIsNotOrigin + ); + }) + } + + #[test] + fn multibatching_batch_v2_should_fail_if_domain_is_invalid() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"wrongdom"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + approvals.sort_by_key(|a| a.from.clone()); + + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::InvalidDomain + ); + }) + } + + #[test] + fn multibatching_batch_v2_should_fail_if_batch_not_signed_by_any_caller() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + approvals.remove(0); + approvals.sort_by_key(|a| a.from.clone()); + + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::InvalidCallOrigin(0) + ); + }) + } + + #[test] + fn multibatching_batch_v2_should_fail_if_caller_signature_incorrect() { + new_test_ext().execute_with(|| { + let call_count = 10; + let signer_count = 10; + + let domain: [u8; 8] = *b"MYTH_NET"; + let bias = [0u8; 32]; + let expires_at = + Timestamp::get() + ::Moment::from(100_000_u64); + + let sender = account(0); + + let mut signers = + Vec::<(EthereumPair, EthereumSigner, AccountId20)>::with_capacity(signer_count); + for _ in 0..signer_count { + let pair: EthereumPair = EthereumPair::generate().0; + let signer: EthereumSigner = pair.public().into(); + let account = signer.clone().into_account(); + signers.push((pair, signer, account)); + } + + let mut calls = BoundedVec::new(); + let iter = (0..call_count).into_iter().zip(signers.iter().cycle()); + for (_, (_, signer, _)) in iter { + let call = frame_system::Call::remark { remark: vec![] }.into(); + calls + .try_push(BatchedCall:: { from: signer.clone().into(), call }) + .ok() + .expect("Mock config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + //eprintln!("test bytes: {}", hex::encode(&pseudo_call_bytes)); + //eprintln!("test hash: {}", hex::encode(hash.into())); + + let mut approvals = BoundedVec::new(); + for (pair, _, account) in &signers { + approvals + .try_push(Approval:: { + from: EthereumSigner::from(account.0).into(), + signature: EthereumSignature::from(pair.sign_prehashed(&hash.into())) + .into(), + }) + .ok() + .expect("Benchmark config must match runtime config for BoundedVec size"); + eprintln!("test from: {:?}", &approvals.last().unwrap().from); + eprintln!("test sig: {:?}", &approvals.last().unwrap().signature); + } + // sign by wrong signer + approvals.sort_by_key(|a| a.from.clone()); + approvals[0].signature = signers[1].0.sign_prehashed(&hash.into()).into(); + + assert_noop!( + Multibatching::batch_v2( + RuntimeOrigin::signed(sender.clone()), + domain, + sender.clone().into(), + bias, + expires_at, + calls, + approvals, + ), + Error::::InvalidSignature(0) + ); + }) + } + } diff --git a/pallets/multibatching/src/weights.rs b/pallets/multibatching/src/weights.rs index e0cef11..f7f65ab 100644 --- a/pallets/multibatching/src/weights.rs +++ b/pallets/multibatching/src/weights.rs @@ -39,6 +39,7 @@ use core::marker::PhantomData; /// Weight functions needed for `pallet_multibatching`. pub trait WeightInfo { fn batch(c: u32, s: u32, ) -> Weight; + fn batch_v2(c: u32, s: u32, ) -> Weight; } /// Weights for `pallet_multibatching` using the Substrate node and recommended hardware. @@ -65,6 +66,28 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Multibatching::Domain` (r:1 w:0) + /// Proof: `Multibatching::Domain` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Multibatching::Applied` (r:1 w:1) + /// Proof: `Multibatching::Applied` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `MaxEncodedLen`) + /// The range of component `c` is `[1, 1000]`. + /// The range of component `s` is `[1, 10]`. + fn batch_v2(c: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `67` + // Estimated: `3497` + // Minimum execution time: 271_000_000 picoseconds. + Weight::from_parts(285_000_000, 3497) + // Standard Error: 1_615 + .saturating_add(Weight::from_parts(1_687_188, 0).saturating_mul(c.into())) + // Standard Error: 160_912 + .saturating_add(Weight::from_parts(27_710_194, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests. @@ -90,4 +113,26 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Multibatching::Domain` (r:1 w:0) + /// Proof: `Multibatching::Domain` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Multibatching::Applied` (r:1 w:1) + /// Proof: `Multibatching::Applied` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `MaxEncodedLen`) + /// The range of component `c` is `[1, 1000]`. + /// The range of component `s` is `[1, 10]`. + fn batch_v2(c: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `67` + // Estimated: `3497` + // Minimum execution time: 271_000_000 picoseconds. + Weight::from_parts(285_000_000, 3497) + // Standard Error: 1_615 + .saturating_add(Weight::from_parts(1_687_188, 0).saturating_mul(c.into())) + // Standard Error: 160_912 + .saturating_add(Weight::from_parts(27_710_194, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/runtime/mainnet/src/weights/pallet_multibatching.rs b/runtime/mainnet/src/weights/pallet_multibatching.rs index e9cbeaf..e3115d9 100644 --- a/runtime/mainnet/src/weights/pallet_multibatching.rs +++ b/runtime/mainnet/src/weights/pallet_multibatching.rs @@ -57,4 +57,25 @@ impl pallet_multibatching::WeightInfo for WeightInfo .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Multibatching::Applied` (r:1 w:1) + /// Proof: `Multibatching::Applied` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `MaxEncodedLen`) + /// The range of component `c` is `[1, 128]`. + /// The range of component `s` is `[1, 128]`. + fn batch_v2(c: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `3497` + // Minimum execution time: 488_143_000 picoseconds. + Weight::from_parts(497_863_000, 0) + .saturating_add(Weight::from_parts(0, 3497)) + // Standard Error: 200_979 + .saturating_add(Weight::from_parts(5_989_676, 0).saturating_mul(c.into())) + // Standard Error: 200_979 + .saturating_add(Weight::from_parts(57_523_530, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } } diff --git a/runtime/testnet/src/weights/pallet_multibatching.rs b/runtime/testnet/src/weights/pallet_multibatching.rs index b2d2a00..995539c 100644 --- a/runtime/testnet/src/weights/pallet_multibatching.rs +++ b/runtime/testnet/src/weights/pallet_multibatching.rs @@ -57,4 +57,25 @@ impl pallet_multibatching::WeightInfo for WeightInfo .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Multibatching::Applied` (r:1 w:1) + /// Proof: `Multibatching::Applied` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `MaxEncodedLen`) + /// The range of component `c` is `[1, 128]`. + /// The range of component `s` is `[1, 128]`. + fn batch_v2(c: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12` + // Estimated: `3497` + // Minimum execution time: 507_113_000 picoseconds. + Weight::from_parts(511_413_000, 0) + .saturating_add(Weight::from_parts(0, 3497)) + // Standard Error: 207_182 + .saturating_add(Weight::from_parts(6_199_404, 0).saturating_mul(c.into())) + // Standard Error: 207_182 + .saturating_add(Weight::from_parts(57_476_835, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } } From b51511738d01d71b94573141aacfbca21313bed8 Mon Sep 17 00:00:00 2001 From: Mikola Samardak Date: Wed, 23 Oct 2024 14:28:36 +0100 Subject: [PATCH 07/10] Fix incorrect signed data in batch_v2, update benchmarks --- pallets/multibatching/src/benchmarking.rs | 59 +++++++++++++++++++++++ pallets/multibatching/src/lib.rs | 2 +- pallets/multibatching/src/tests.rs | 6 +-- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/pallets/multibatching/src/benchmarking.rs b/pallets/multibatching/src/benchmarking.rs index 8cffda5..03b226e 100644 --- a/pallets/multibatching/src/benchmarking.rs +++ b/pallets/multibatching/src/benchmarking.rs @@ -98,5 +98,64 @@ pub mod benchmarks { _(RawOrigin::Signed(sender), domain, sender.into(), bias, expires_at, calls, approvals); } + #[benchmark] + fn batch_v2(c: Linear<1, { T::MaxCalls::get() }>, s: Linear<1, { T::MaxCalls::get() }>) { + let call_count = c as usize; + let signer_count = s as usize; + + let domain: [u8; 8] = T::Domain::get(); + let bias = [0u8; 32]; + let expires_at = Timestamp::::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:: { from: signer.clone().into(), call }) + .expect("Benchmark config must match runtime config for BoundedVec size"); + } + + let pseudo_call: ::RuntimeCall = Call::::batch_v2 { + domain, + sender: sender.into(), + bias, + expires_at, + calls: calls.clone(), + approvals: BoundedVec::new(), + } + .into(); + let pseudo_call_bytes = pseudo_call.encode(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let hash = keccak_256(&pseudo_call_bytes); + + let mut approvals = BoundedVec::new(); + for (public, _signer, account) in &signers { + approvals + .try_push(Approval:: { + 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()); + + #[extrinsic_call] + Pallet::::batch_v2(RawOrigin::Signed(sender), domain, sender.into(), bias, expires_at, calls, approvals); + } + impl_benchmark_test_suite!(Multibatching, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/multibatching/src/lib.rs b/pallets/multibatching/src/lib.rs index d344c7b..95a83bd 100644 --- a/pallets/multibatching/src/lib.rs +++ b/pallets/multibatching/src/lib.rs @@ -382,7 +382,7 @@ pub mod pallet { let bytes = Batch { pallet_index: Self::index() as u8, - call_index: 0, + call_index: 1, domain, sender: sender.clone(), bias, diff --git a/pallets/multibatching/src/tests.rs b/pallets/multibatching/src/tests.rs index b8c5e16..ec41d37 100644 --- a/pallets/multibatching/src/tests.rs +++ b/pallets/multibatching/src/tests.rs @@ -662,7 +662,7 @@ mod multibatching_test { .expect("Mock config must match runtime config for BoundedVec size"); } - let pseudo_call: ::RuntimeCall = Call::::batch { + let pseudo_call: ::RuntimeCall = Call::::batch_v2 { domain, sender: sender.into(), bias, @@ -880,7 +880,7 @@ mod multibatching_test { .expect("Mock config must match runtime config for BoundedVec size"); } - let pseudo_call: ::RuntimeCall = Call::::batch { + let pseudo_call: ::RuntimeCall = Call::::batch_v2 { domain, sender: sender.into(), bias, @@ -1124,7 +1124,7 @@ mod multibatching_test { .expect("Mock config must match runtime config for BoundedVec size"); } - let pseudo_call: ::RuntimeCall = Call::::batch { + let pseudo_call: ::RuntimeCall = Call::::batch_v2 { domain, sender: sender.into(), bias, From ff1a5b0f7eaaf1fc1bed4a8bd0e0c458771080f2 Mon Sep 17 00:00:00 2001 From: Mikola Samardak Date: Thu, 31 Oct 2024 15:12:09 +0000 Subject: [PATCH 08/10] cargo fmt --- pallets/multibatching/src/benchmarking.rs | 12 ++++++++++-- pallets/multibatching/src/lib.rs | 2 +- pallets/multibatching/src/tests.rs | 17 ++++++++--------- primitives/xcm/src/lib.rs | 3 ++- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pallets/multibatching/src/benchmarking.rs b/pallets/multibatching/src/benchmarking.rs index 03b226e..5abb469 100644 --- a/pallets/multibatching/src/benchmarking.rs +++ b/pallets/multibatching/src/benchmarking.rs @@ -136,7 +136,7 @@ pub mod benchmarks { } .into(); let pseudo_call_bytes = pseudo_call.encode(); - let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); + let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); let mut approvals = BoundedVec::new(); @@ -154,7 +154,15 @@ pub mod benchmarks { approvals.sort_by_key(|a| a.from.clone()); #[extrinsic_call] - Pallet::::batch_v2(RawOrigin::Signed(sender), domain, sender.into(), bias, expires_at, calls, approvals); + Pallet::::batch_v2( + RawOrigin::Signed(sender), + domain, + sender.into(), + bias, + expires_at, + calls, + approvals, + ); } impl_benchmark_test_suite!(Multibatching, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/pallets/multibatching/src/lib.rs b/pallets/multibatching/src/lib.rs index 95a83bd..a7a247a 100644 --- a/pallets/multibatching/src/lib.rs +++ b/pallets/multibatching/src/lib.rs @@ -322,7 +322,7 @@ pub mod pallet { /// This function works the same as [Pallet::batch], but the bytes signed by /// approvers must be wrapped in between ... . /// This is how the rawSign is currently implemented in modern substrate clients. - /// + /// #[pallet::call_index(1)] #[pallet::weight({ let dispatch_infos = calls.iter().map(|call| call.call.get_dispatch_info()).collect::>(); diff --git a/pallets/multibatching/src/tests.rs b/pallets/multibatching/src/tests.rs index ec41d37..e0cf17f 100644 --- a/pallets/multibatching/src/tests.rs +++ b/pallets/multibatching/src/tests.rs @@ -670,7 +670,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); @@ -745,7 +745,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = blake2_256(&pseudo_call_bytes); @@ -823,7 +823,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let _hash = keccak_256(&pseudo_call_bytes); @@ -888,7 +888,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); @@ -976,7 +976,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); @@ -1054,7 +1054,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); @@ -1132,7 +1132,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); @@ -1211,7 +1211,7 @@ mod multibatching_test { calls: calls.clone(), approvals: BoundedVec::new(), } - .into(); + .into(); let pseudo_call_bytes = pseudo_call.encode(); let pseudo_call_bytes = [b"", &pseudo_call_bytes[..], b""].concat(); let hash = keccak_256(&pseudo_call_bytes); @@ -1250,5 +1250,4 @@ mod multibatching_test { ); }) } - } diff --git a/primitives/xcm/src/lib.rs b/primitives/xcm/src/lib.rs index 7d40f29..5f9f47d 100644 --- a/primitives/xcm/src/lib.rs +++ b/primitives/xcm/src/lib.rs @@ -10,7 +10,8 @@ pub struct SignedToAccountId20( sp_std::marker::PhantomData<(Origin, AccountId, Network)>, ); impl, Network: Get> - sp_runtime::traits::TryConvert for SignedToAccountId20 + sp_runtime::traits::TryConvert + for SignedToAccountId20 where Origin::PalletsOrigin: From> + TryInto, Error = Origin::PalletsOrigin>, From ccb3ba654593019963226676543e64f6d0445293 Mon Sep 17 00:00:00 2001 From: Mikola Samardak Date: Thu, 31 Oct 2024 15:25:11 +0000 Subject: [PATCH 09/10] Fix build failure due to cargofmt version mismatch --- primitives/xcm/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/primitives/xcm/src/lib.rs b/primitives/xcm/src/lib.rs index 5f9f47d..7d40f29 100644 --- a/primitives/xcm/src/lib.rs +++ b/primitives/xcm/src/lib.rs @@ -10,8 +10,7 @@ pub struct SignedToAccountId20( sp_std::marker::PhantomData<(Origin, AccountId, Network)>, ); impl, Network: Get> - sp_runtime::traits::TryConvert - for SignedToAccountId20 + sp_runtime::traits::TryConvert for SignedToAccountId20 where Origin::PalletsOrigin: From> + TryInto, Error = Origin::PalletsOrigin>, From 92405604a06b465cead8b21d922d162377918106 Mon Sep 17 00:00:00 2001 From: Mikola Samardak Date: Thu, 31 Oct 2024 15:36:09 +0000 Subject: [PATCH 10/10] Increment spec_version in testnet and mainnet runtimes --- runtime/mainnet/src/lib.rs | 2 +- runtime/testnet/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/mainnet/src/lib.rs b/runtime/mainnet/src/lib.rs index ef81e41..b448bab 100644 --- a/runtime/mainnet/src/lib.rs +++ b/runtime/mainnet/src/lib.rs @@ -226,7 +226,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("mythos"), impl_name: create_runtime_str!("mythos"), authoring_version: 1, - spec_version: 1010, + spec_version: 1011, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtime/testnet/src/lib.rs b/runtime/testnet/src/lib.rs index a4c6259..3cc18e0 100644 --- a/runtime/testnet/src/lib.rs +++ b/runtime/testnet/src/lib.rs @@ -244,7 +244,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("muse"), impl_name: create_runtime_str!("muse"), authoring_version: 1, - spec_version: 1019, + spec_version: 1020, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1,