From 1e501b501df2a3e750529f6b6159cae072746b26 Mon Sep 17 00:00:00 2001 From: Jay White Date: Thu, 17 Sep 2026 13:50:21 -0400 Subject: [PATCH 1/9] test: add unit test for `convert_account_id` --- sxt-core/src/utils.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sxt-core/src/utils.rs b/sxt-core/src/utils.rs index 43be2823..686a364c 100644 --- a/sxt-core/src/utils.rs +++ b/sxt-core/src/utils.rs @@ -91,3 +91,32 @@ pub fn proof_of_sql_bincode_config() -> impl binc .with_big_endian() .with_limit::() } + +#[cfg(test)] +mod tests { + use polkadot_sdk::frame_support::derive_impl; + + use super::*; + + polkadot_sdk::frame_support::construct_runtime!( + pub enum Test { + System: frame_system, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Test { + type Block = frame_system::mocking::MockBlock; + type AccountId = AccountId32; + type Lookup = sp_runtime::traits::IdentityLookup; + } + + #[test] + fn convert_account_id_round_trips_through_accountid32() { + let account = AccountId32::new([7u8; 32]); + + let converted = convert_account_id::(account.clone()).unwrap(); + + assert_eq!(converted, account); + } +} From 8fb2ff81b397df5fe1add6a0bb2b47c4ec442812 Mon Sep 17 00:00:00 2001 From: Jay White Date: Thu, 17 Sep 2026 13:50:21 -0400 Subject: [PATCH 2/9] feat: add `table_treasury_account` helper This defines the account id associated with a TableIdentifier. This is a domain key: `sxt/table` that ensures this account id will not collide with any other account ids --- sxt-core/src/utils.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/sxt-core/src/utils.rs b/sxt-core/src/utils.rs index 686a364c..573852fb 100644 --- a/sxt-core/src/utils.rs +++ b/sxt-core/src/utils.rs @@ -1,7 +1,8 @@ use alloc::vec::Vec; -use codec::Decode; +use codec::{Decode, Encode}; use polkadot_sdk::frame_system::Config as SystemConfig; +use polkadot_sdk::sp_core::blake2_256; use polkadot_sdk::sp_core::crypto::AccountId32; use polkadot_sdk::sp_runtime::traits::StaticLookup; use polkadot_sdk::sp_runtime::DispatchError; @@ -71,6 +72,19 @@ pub fn eth_address_to_substrate_account_id( try_get_account_from_20_byte_vec::(raw_bytes) } +/// Takes a table identifier and returns the deterministic `AccountId` of its treasury. +pub fn table_treasury_account( + table: &crate::tables::TableIdentifier, +) -> Option +where + T::AccountId: Decode, +{ + convert_account_id::(AccountId32::new( + (b"sxt/table", &table.namespace, &table.name).using_encoded(blake2_256), + )) + .ok() +} + /// Convert the supplied AccountId32 to the runtime's AccountId type pub fn convert_account_id( account_id32: AccountId32, @@ -95,8 +109,10 @@ pub fn proof_of_sql_bincode_config() -> impl binc #[cfg(test)] mod tests { use polkadot_sdk::frame_support::derive_impl; + use polkadot_sdk::sp_core::crypto::Ss58Codec; use super::*; + use crate::tables::{TableIdentifier, TableName, TableNamespace}; polkadot_sdk::frame_support::construct_runtime!( pub enum Test { @@ -119,4 +135,22 @@ mod tests { assert_eq!(converted, account); } + + #[test] + fn table_treasury_account_matches_known_derivation() { + let table = TableIdentifier { + namespace: TableNamespace::try_from( + b"EACAGGREGATORPROXY_V1_FA74C8D117B4BD0F3F9C6B10F6C47CE66DC499A0".to_vec(), + ) + .unwrap(), + name: TableName::try_from(b"OWNERSHIP_TRANSFERRED".to_vec()).unwrap(), + }; + + let treasury = table_treasury_account::(&table).unwrap(); + + assert_eq!( + treasury.to_ss58check(), + "5FgaiRaTgngHbkoLipwLVHXSUyHuyUvBHXW1HwTTDNfp5HTs" + ); + } } From 323c152cf6bc8cc23d1eaa30f5a75bc68152bf7a Mon Sep 17 00:00:00 2001 From: Jay White Date: Thu, 17 Sep 2026 13:51:14 -0400 Subject: [PATCH 3/9] refactor: have `finalize_quorum` take `data_quorum` by reference This doesn't change anything since `finalize_quorum` already only uses it by reference. --- pallets/indexing/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/indexing/src/lib.rs b/pallets/indexing/src/lib.rs index 3ea126d6..fe130873 100644 --- a/pallets/indexing/src/lib.rs +++ b/pallets/indexing/src/lib.rs @@ -511,7 +511,7 @@ pub mod pallet { &table_insert_quorum, &quorum_scope, )? { - finalize_quorum::(data_quorum, data, block_number, who)?; + finalize_quorum::(&data_quorum, data, block_number, who)?; } Ok(()) @@ -643,7 +643,7 @@ pub mod pallet { /// - emitting `QuorumReached` event /// - cleaning up submissions fn finalize_quorum( - quorum: DataQuorum, + quorum: &DataQuorum, row_data: RowData, block_number: Option, submitter: T::AccountId, @@ -652,7 +652,7 @@ pub mod pallet { T: Config, I: NativeApi, { - clean_up_and_record_quorum::(&quorum); + clean_up_and_record_quorum::(quorum); // Deserialize into Arrow-compatible OnChainTable let table_bytes = I::record_batch_to_onchain(sxt_core::native::RowData { row_data }) From e85ababdbce3276178ee22442f409469c2f634a6 Mon Sep 17 00:00:00 2001 From: Jay White Date: Mon, 28 Sep 2026 20:48:27 -0400 Subject: [PATCH 4/9] refactor: pass `Call` into `submit_data_inner` --- pallets/indexing/src/lib.rs | 44 +++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/pallets/indexing/src/lib.rs b/pallets/indexing/src/lib.rs index fe130873..c57c5735 100644 --- a/pallets/indexing/src/lib.rs +++ b/pallets/indexing/src/lib.rs @@ -230,6 +230,8 @@ pub mod pallet { ArrowRowCountOutOfBounds, /// Arrow schema contains no fields. ArrowSchemaMissingFields, + /// The call is not a data submission. + UnsupportedCall, } #[pallet::call] @@ -271,7 +273,14 @@ pub mod pallet { batch_id: BatchId, data: RowData, ) -> DispatchResult { - submit_data_inner::(origin, table, batch_id, data, None) + submit_data_inner::( + origin, + Call::submit_data { + table, + batch_id, + data, + }, + ) } /// Submit an IPC-formatted record batch for a given table with block number metadata. @@ -310,7 +319,15 @@ pub mod pallet { data: RowData, block_number: u64, ) -> DispatchResult { - submit_data_inner::(origin, table, batch_id, data, Some(block_number)) + submit_data_inner::( + origin, + Call::submit_blockchain_data { + table, + batch_id, + data, + block_number, + }, + ) } /// Set the block number for a table. @@ -481,19 +498,28 @@ pub mod pallet { Ok((quorum_scope, table_insert_quorum)) } - fn submit_data_inner( - origin: OriginFor, - table: TableIdentifier, - outer_batch_id: BatchId, - data: RowData, - block_number: Option, - ) -> DispatchResult + fn submit_data_inner(origin: OriginFor, call: Call) -> DispatchResult where T: Config, I: NativeApi, { let who = ensure_signed(origin.clone())?; + let (table, outer_batch_id, data, block_number) = match call { + Call::submit_data { + table, + batch_id, + data, + } => (table, batch_id, data, None), + Call::submit_blockchain_data { + table, + batch_id, + data, + block_number, + } => (table, batch_id, data, Some(block_number)), + _ => Err(Error::::UnsupportedCall)?, + }; + let (quorum_scope, table_insert_quorum) = get_submission_permissions::(origin, &table)?; From 1fcba4f848e1bb50db43c68b5e4d2bc56a52e15a Mon Sep 17 00:00:00 2001 From: Jay White Date: Thu, 17 Sep 2026 13:51:23 -0400 Subject: [PATCH 5/9] chore: require `pallet_balances`/`pallet_transaction_payment` in pallet-indexing's `Config` Needed so the pallet can later draw on a table's treasury balance and compute the real extrinsic fee for a submission when refunding it. --- pallets/indexing/Cargo.toml | 4 ++-- pallets/indexing/src/lib.rs | 4 +++- pallets/indexing/src/mock.rs | 30 ++++++++++++++++++++++++++++++ pallets/smartcontracts/src/mock.rs | 21 +++++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/pallets/indexing/Cargo.toml b/pallets/indexing/Cargo.toml index 5135f293..ceef8887 100644 --- a/pallets/indexing/Cargo.toml +++ b/pallets/indexing/Cargo.toml @@ -21,7 +21,7 @@ scale-info = { features = [ "derive", ], workspace = true } -polkadot-sdk = { workspace = true, features = ["frame-benchmarking", "frame-support", "frame-system", "pallet-session", "sp-runtime", "sp-core"]} +polkadot-sdk = { workspace = true, features = ["frame-benchmarking", "frame-support", "frame-system", "pallet-session", "pallet-balances", "pallet-transaction-payment", "sp-runtime", "sp-core"]} pallet-commitments.workspace = true pallet-permissions.workspace = true @@ -40,7 +40,7 @@ arrow-ipc-no-std.workspace = true snafu.workspace = true [dev-dependencies] -polkadot-sdk = { workspace = true, features = ["sp-staking", "frame-election-provider-support", "pallet-staking-reward-curve", "pallet-timestamp", "pallet-balances", "pallet-staking", "sp-core", "sp-io", "sp-runtime"]} +polkadot-sdk = { workspace = true, features = ["sp-staking", "frame-election-provider-support", "pallet-staking-reward-curve", "pallet-timestamp", "pallet-balances", "pallet-staking", "pallet-transaction-payment", "pallet-utility", "sp-core", "sp-io", "sp-runtime"]} proof-of-sql-static-setups = { workspace = true, features = ["io"] } native.workspace = true diff --git a/pallets/indexing/src/lib.rs b/pallets/indexing/src/lib.rs index c57c5735..51176f81 100644 --- a/pallets/indexing/src/lib.rs +++ b/pallets/indexing/src/lib.rs @@ -41,10 +41,10 @@ pub mod pallet { use pallet_tables::BlockEnforcement; use polkadot_sdk::frame_support::pallet_prelude::*; use polkadot_sdk::frame_support::Blake2_128Concat; - use polkadot_sdk::frame_system; use polkadot_sdk::frame_system::pallet_prelude::*; use polkadot_sdk::sp_runtime::traits::Hash; use polkadot_sdk::sp_runtime::BoundedVec; + use polkadot_sdk::{frame_system, pallet_balances, pallet_transaction_payment}; use proof_of_sql_commitment_map::CommitmentScheme; use sxt_core::permissions::{IndexingPalletPermission, PermissionLevel}; use sxt_core::record_batch::record_batch_bytes_dimensions; @@ -67,6 +67,8 @@ pub mod pallet { + pallet_commitments::Config + pallet_tables::Config + pallet_system_tables::Config + + pallet_balances::Config + + pallet_transaction_payment::Config { /// Binding for the runtime event, typically provided by an implementation /// in runtime/lib.rs diff --git a/pallets/indexing/src/mock.rs b/pallets/indexing/src/mock.rs index 49f5138e..5fd0f004 100644 --- a/pallets/indexing/src/mock.rs +++ b/pallets/indexing/src/mock.rs @@ -6,7 +6,10 @@ use polkadot_sdk::frame_election_provider_support::bounds::{ use polkadot_sdk::frame_election_provider_support::{onchain, SequentialPhragmen}; use polkadot_sdk::frame_support::pallet_prelude::ConstU32; use polkadot_sdk::frame_support::traits::ConstU128; +use polkadot_sdk::frame_support::weights::ConstantMultiplier; use polkadot_sdk::frame_support::{derive_impl, parameter_types}; +#[allow(deprecated)] +use polkadot_sdk::pallet_transaction_payment::CurrencyAdapter; use polkadot_sdk::sp_core::{ConstU64, H256}; use polkadot_sdk::sp_runtime::traits::{IdentityLookup, OpaqueKeys}; use polkadot_sdk::sp_runtime::{BuildStorage, KeyTypeId}; @@ -18,6 +21,8 @@ use polkadot_sdk::{ pallet_staking, pallet_staking_reward_curve, pallet_timestamp, + pallet_transaction_payment, + pallet_utility, sp_core, sp_io, sp_runtime, @@ -44,6 +49,8 @@ frame_support::construct_runtime!( SystemTables: pallet_system_tables, Balances: pallet_balances, Staking: pallet_staking, + TransactionPayment: pallet_transaction_payment, + Utility: pallet_utility, } ); @@ -77,6 +84,29 @@ impl pallet_balances::Config for Test { type MaxFreezes = (); } +parameter_types! { + pub const WeightFeePerRefTime: Balance = 1; + pub const TransactionByteFee: Balance = 1; + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_transaction_payment::Config for Test { + type RuntimeEvent = RuntimeEvent; + #[allow(deprecated)] + type OnChargeTransaction = CurrencyAdapter; + type WeightToFee = ConstantMultiplier; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = (); + type OperationalFeeMultiplier = OperationalFeeMultiplier; +} + +impl pallet_utility::Config for Test { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = (); +} + impl pallet_timestamp::Config for Test { type Moment = u64; type OnTimestampSet = (); diff --git a/pallets/smartcontracts/src/mock.rs b/pallets/smartcontracts/src/mock.rs index 67e169bc..ab148ee5 100644 --- a/pallets/smartcontracts/src/mock.rs +++ b/pallets/smartcontracts/src/mock.rs @@ -4,7 +4,10 @@ use polkadot_sdk::frame_election_provider_support::bounds::{ ElectionBoundsBuilder, }; use polkadot_sdk::frame_election_provider_support::{onchain, SequentialPhragmen}; +use polkadot_sdk::frame_support::weights::ConstantMultiplier; use polkadot_sdk::frame_support::{derive_impl, parameter_types}; +#[allow(deprecated)] +use polkadot_sdk::pallet_transaction_payment::CurrencyAdapter; use polkadot_sdk::sp_core::{ConstU32, ConstU64, H256}; use polkadot_sdk::sp_runtime::traits::{IdentityLookup, OpaqueKeys}; use polkadot_sdk::sp_runtime::{BuildStorage, KeyTypeId}; @@ -16,6 +19,7 @@ use polkadot_sdk::{ pallet_staking, pallet_staking_reward_curve, pallet_timestamp, + pallet_transaction_payment, sp_core, sp_io, sp_runtime, @@ -43,6 +47,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, ZkPay: pallet_zkpay, Staking: pallet_staking, + TransactionPayment: pallet_transaction_payment, } ); @@ -76,6 +81,22 @@ impl pallet_balances::Config for Test { type MaxFreezes = (); } +parameter_types! { + pub const WeightFeePerRefTime: Balance = 1; + pub const TransactionByteFee: Balance = 1; + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_transaction_payment::Config for Test { + type RuntimeEvent = RuntimeEvent; + #[allow(deprecated)] + type OnChargeTransaction = CurrencyAdapter; + type WeightToFee = ConstantMultiplier; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = (); + type OperationalFeeMultiplier = OperationalFeeMultiplier; +} + pallet_staking_reward_curve::build! { const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( min_inflation: 0_025_000, From 12b42aaaf142916bec18bbd66b48c1887802f4e7 Mon Sep 17 00:00:00 2001 From: Jay White Date: Thu, 17 Sep 2026 13:51:23 -0400 Subject: [PATCH 6/9] feat: add `REFUND_PERCENTAGE_DOMAIN` table metadata domain This is the `pallet_tables::TableMetadata` domain key that will store a table's submission fee refund percentage. --- sxt-core/src/indexing.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sxt-core/src/indexing.rs b/sxt-core/src/indexing.rs index 1d087c4f..dd585afe 100644 --- a/sxt-core/src/indexing.rs +++ b/sxt-core/src/indexing.rs @@ -21,6 +21,10 @@ pub type BatchId = BoundedVec>; /// The maximum number of submitters for a particular batch id pub const MAX_SUBMITTERS: u32 = 32; + +/// `TableMetadata` domain for a table's fee refund percentage as a SCALE `u16` (`100` = fee paid, above `100` pays more); absent or invalid means no refund. +pub const REFUND_PERCENTAGE_DOMAIN: &[u8] = b"REFUND_PERCENTAGE"; + /// A list of submitter account IDs, We use the generic to allow us to use the runtime's /// accountId, regardless of the underlying implementation of that Id pub type SubmitterList = BoundedBTreeSet>; From 67075ad7bf468361fe3ca9c9a234a0f1fc5e619b Mon Sep 17 00:00:00 2001 From: Jay White Date: Tue, 29 Sep 2026 10:48:48 -0400 Subject: [PATCH 7/9] feat: add `refund_quorum` for refunding quorum submitters --- pallets/indexing/src/lib.rs | 98 ++++++++++++++++++++++++- pallets/indexing/src/tests.rs | 134 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 2 deletions(-) diff --git a/pallets/indexing/src/lib.rs b/pallets/indexing/src/lib.rs index 51176f81..a3575086 100644 --- a/pallets/indexing/src/lib.rs +++ b/pallets/indexing/src/lib.rs @@ -39,16 +39,22 @@ pub mod pallet { use on_chain_table::OnChainTable; use pallet_tables::pallet::BlockEnforcementMode; use pallet_tables::BlockEnforcement; + use polkadot_sdk::frame_support::dispatch::DispatchInfo; use polkadot_sdk::frame_support::pallet_prelude::*; + use polkadot_sdk::frame_support::traits::fungible::Mutate; + use polkadot_sdk::frame_support::traits::tokens::Preservation; use polkadot_sdk::frame_support::Blake2_128Concat; use polkadot_sdk::frame_system::pallet_prelude::*; - use polkadot_sdk::sp_runtime::traits::Hash; - use polkadot_sdk::sp_runtime::BoundedVec; + use polkadot_sdk::pallet_transaction_payment::{FeeDetails, InclusionFee, OnChargeTransaction}; + use polkadot_sdk::sp_runtime::traits::{Dispatchable, Hash, Zero}; + use polkadot_sdk::sp_runtime::{BoundedVec, Saturating}; use polkadot_sdk::{frame_system, pallet_balances, pallet_transaction_payment}; use proof_of_sql_commitment_map::CommitmentScheme; use sxt_core::permissions::{IndexingPalletPermission, PermissionLevel}; use sxt_core::record_batch::record_batch_bytes_dimensions; use sxt_core::tables::{InsertQuorumSize, QuorumScope, TableIdentifier}; + use sxt_core::utils::table_treasury_account; + use sxt_core::ByteString; use super::*; @@ -168,6 +174,28 @@ pub mod pallet { /// Voters against this quorum dissents: BoundedBTreeSet>, }, + + /// The submission fee for a finalized quorum has been refunded to its submitters. + RefundProcessed { + /// The table identifier + table: TableIdentifier, + /// The batch that was refunded + batch_id: BatchId, + /// The amount refunded to each submitter + refund: T::Balance, + }, + + /// Emitted when a refund transfer to a submitter fails. + RefundError { + /// The table identifier + table: TableIdentifier, + /// The batch whose refund failed + batch_id: BatchId, + /// The submitter who was to receive the refund + recipient: T::AccountId, + /// The error received while processing the transfer + error: DispatchError, + }, } #[pallet::error] @@ -545,6 +573,72 @@ pub mod pallet { Ok(()) } + /// Refunds each quorum submitter the weight and length fee of their call, scaled by [`REFUND_PERCENTAGE_DOMAIN`]. + #[cfg_attr(not(test), expect(dead_code))] + pub(crate) fn refund_quorum( + quorum: DataQuorum, + weight: Weight, + len: u32, + ) where + T: Config, + I: NativeApi, + T::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, + { + let Some(percentage) = ByteString::try_from(REFUND_PERCENTAGE_DOMAIN.to_vec()) + .ok() + .and_then(|domain| pallet_tables::TableMetadata::::get(&domain, &quorum.table)) + .and_then(|bytes| u16::decode(&mut bytes.as_slice()).ok()) + else { + return; + }; + + let Some(treasury) = table_treasury_account::(&quorum.table) else { + // Unreachable unless the runtime's `AccountId` stops decoding from `AccountId32`. + return; + }; + + let info = DispatchInfo { + weight, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; + let details = + pallet_transaction_payment::Pallet::::compute_fee_details(len, &info, Zero::zero()); + let cost = FeeDetails { + inclusion_fee: details.inclusion_fee.map(|fee| InclusionFee { + base_fee: Zero::zero(), + ..fee + }), + ..details + } + .final_fee(); + let refund = cost.saturating_mul(percentage.into()) / 100u16.into(); + + for recipient in quorum.agreements { + if let Err(error) = pallet_balances::Pallet::::transfer( + &treasury, + &recipient, + refund, + Preservation::Expendable, + ) { + Pallet::::deposit_event(Event::RefundError { + table: quorum.table.clone(), + batch_id: quorum.batch_id.clone(), + recipient, + error, + }); + } + } + + Pallet::::deposit_event(Event::RefundProcessed { + table: quorum.table, + batch_id: quorum.batch_id, + refund, + }); + } + /// Submit data and check if we have a quorum. /// /// If quorum is reached, the associated [`DataQuorum`] is returned, otherwise returns `None`. diff --git a/pallets/indexing/src/tests.rs b/pallets/indexing/src/tests.rs index a31dfb27..fa97f4c9 100644 --- a/pallets/indexing/src/tests.rs +++ b/pallets/indexing/src/tests.rs @@ -14,6 +14,8 @@ use pallet_tables::{CommitmentCreationCmd, UpdateTable}; use polkadot_sdk::frame_support::__private::RuntimeDebug; use polkadot_sdk::frame_support::dispatch::DispatchResult; use polkadot_sdk::frame_support::pallet_prelude::TypeInfo; +use polkadot_sdk::frame_support::traits::fungible::Mutate; +use polkadot_sdk::frame_support::weights::Weight; use polkadot_sdk::frame_support::{assert_err, assert_ok}; use polkadot_sdk::frame_system::ensure_signed; use polkadot_sdk::sp_core::Hasher; @@ -28,10 +30,13 @@ use sxt_core::tables::{ InsertQuorumSize, QuorumScope, TableIdentifier, + TableMetadataBytes, TableName, TableNamespace, TableType, }; +use sxt_core::utils::table_treasury_account; +use sxt_core::ByteString; use crate::mock::*; use crate::{build_inner_batch_id, BatchId, Event, RowData}; @@ -101,6 +106,17 @@ fn record_batch_to_row_data(batch: RecordBatch, schema: Arc) -> RowData RowData::try_from(data).unwrap() } +fn set_refund_percentage(table: &TableIdentifier, percentage: u16) { + let domain = ByteString::try_from(crate::REFUND_PERCENTAGE_DOMAIN.to_vec()).unwrap(); + let bytes = TableMetadataBytes::try_from(percentage.encode()).unwrap(); + assert_ok!(Tables::set_table_metadata( + RuntimeOrigin::root(), + domain, + table.clone(), + Some(bytes), + )); +} + fn sample_table_definition() -> (TableIdentifier, CreateStatement) { let table_id = TableIdentifier { namespace: TableNamespace::try_from(b"TEST_NAMESPACE".to_owned().to_vec()).unwrap(), @@ -2517,3 +2533,121 @@ fn submit_empty_blocks_respects_quorum() { ); }); } + +#[test] +fn refund_quorum_pays_each_agreement_its_fee_scaled_by_percentage() { + for (percentage, expected_refund) in [(100, 1_001_000), (150, 1_501_500), (200, 2_002_000)] { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let submitters = [ + sp_runtime::AccountId32::new([1; 32]), + sp_runtime::AccountId32::new([2; 32]), + ]; + let quorum = crate::DataQuorum { + table: sample_table_definition().0, + batch_id: BatchId::try_from(b"test_batch".to_vec()).unwrap(), + data_hash: Default::default(), + block_number: Default::default(), + agreements: std::collections::BTreeSet::from(submitters.clone()) + .try_into() + .unwrap(), + dissents: Default::default(), + quorum_scope: QuorumScope::Public, + }; + set_refund_percentage(&quorum.table, percentage); + let treasury = table_treasury_account::(&quorum.table).unwrap(); + assert_ok!(Balances::mint_into(&treasury, 1_000_000_000)); + + crate::refund_quorum::( + quorum.clone(), + Weight::from_parts(1_000_000, 0), + 1_000, + ); + + for submitter in &submitters { + assert_eq!(Balances::free_balance(submitter), expected_refund); + } + assert_eq!( + Balances::free_balance(&treasury), + 1_000_000_000 - 2 * expected_refund + ); + assert_eq!( + System::read_events_for_pallet::>(), + vec![Event::RefundProcessed { + table: quorum.table, + batch_id: quorum.batch_id, + refund: expected_refund, + }] + ); + }); + } +} + +#[test] +fn refund_quorum_skips_when_percentage_is_missing_or_invalid() { + for metadata in [None, Some(vec![0u8])] { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let submitter = sp_runtime::AccountId32::new([1; 32]); + let quorum = crate::DataQuorum { + table: sample_table_definition().0, + batch_id: BatchId::try_from(b"test_batch".to_vec()).unwrap(), + data_hash: Default::default(), + block_number: Default::default(), + agreements: std::collections::BTreeSet::from([submitter.clone()]) + .try_into() + .unwrap(), + dissents: Default::default(), + quorum_scope: QuorumScope::Public, + }; + if let Some(bytes) = metadata { + assert_ok!(Tables::set_table_metadata( + RuntimeOrigin::root(), + ByteString::try_from(crate::REFUND_PERCENTAGE_DOMAIN.to_vec()).unwrap(), + quorum.table.clone(), + Some(TableMetadataBytes::try_from(bytes).unwrap()), + )); + } + assert_ok!(Balances::mint_into( + &table_treasury_account::(&quorum.table).unwrap(), + 1_000_000_000 + )); + + crate::refund_quorum::(quorum, Weight::from_parts(1_000_000, 0), 1_000); + + assert_eq!(Balances::free_balance(&submitter), 0); + assert!(System::read_events_for_pallet::>().is_empty()); + }); + } +} + +#[test] +fn refund_quorum_emits_refund_error_when_treasury_is_unfunded() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let submitter = sp_runtime::AccountId32::new([1; 32]); + let quorum = crate::DataQuorum { + table: sample_table_definition().0, + batch_id: BatchId::try_from(b"test_batch".to_vec()).unwrap(), + data_hash: Default::default(), + block_number: Default::default(), + agreements: std::collections::BTreeSet::from([submitter.clone()]) + .try_into() + .unwrap(), + dissents: Default::default(), + quorum_scope: QuorumScope::Public, + }; + set_refund_percentage(&quorum.table, 100); + + crate::refund_quorum::(quorum.clone(), Weight::from_parts(1_000_000, 0), 1_000); + + assert_eq!(Balances::free_balance(&submitter), 0); + assert!(matches!( + System::read_events_for_pallet::>().as_slice(), + [ + Event::RefundError { table, batch_id, recipient, .. }, + Event::RefundProcessed { .. }, + ] if recipient == &submitter && table == &quorum.table && batch_id == &quorum.batch_id + )); + }); +} From 556fb73f8fcfa1a893af659a84a767740341e284 Mon Sep 17 00:00:00 2001 From: Jay White Date: Tue, 29 Sep 2026 10:48:55 -0400 Subject: [PATCH 8/9] feat: refund submission fee to quorum submitters In this implementation, only agreements are refunded. Late submissions and dissents are not refunded. That change is left for later. --- pallets/indexing/src/benchmarking.rs | 78 ++++++++----- pallets/indexing/src/lib.rs | 10 +- pallets/indexing/src/tests.rs | 164 ++++++++++++++++++++++++++- 3 files changed, 223 insertions(+), 29 deletions(-) diff --git a/pallets/indexing/src/benchmarking.rs b/pallets/indexing/src/benchmarking.rs index 8062411c..7ca87bc7 100644 --- a/pallets/indexing/src/benchmarking.rs +++ b/pallets/indexing/src/benchmarking.rs @@ -2,9 +2,12 @@ use alloc::vec; use polkadot_sdk::frame_benchmarking::v2::*; +use polkadot_sdk::frame_support::dispatch::DispatchInfo; use polkadot_sdk::frame_system; use polkadot_sdk::frame_system::RawOrigin; +use polkadot_sdk::pallet_transaction_payment::{self, OnChargeTransaction}; use polkadot_sdk::sp_core::crypto::Ss58Codec; +use polkadot_sdk::sp_runtime::traits::Dispatchable; use super::*; #[cfg(test)] @@ -17,25 +20,37 @@ use crate::Pallet as Indexing; where ::AccountId: Ss58Codec, I: NativeApi, + T::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, )] mod benchmarks { + use codec::Encode; use native_api::NativeApi; use on_chain_table::{OnChainColumn, OnChainTable}; use pallet_tables::benchmarking::schema_bytes_and_ddl_and_source; use pallet_tables::pallet::BlockEnforcementMode; use pallet_tables::{BlockEnforcement, CommitmentCreationCmd, UpdateTable}; + use polkadot_sdk::frame_support::traits::fungible::Mutate; + use polkadot_sdk::frame_support::traits::Get; + use polkadot_sdk::pallet_balances; + use polkadot_sdk::sp_runtime::traits::Bounded; use proof_of_sql_commitment_map::CommitmentSchemeFlags; use sqlparser::ast::Ident; + use sxt_core::indexing::REFUND_PERCENTAGE_DOMAIN; use sxt_core::permissions::{IndexingPalletPermission, PermissionLevel, PermissionList}; use sxt_core::tables::{ InsertQuorumSize, Source, TableIdentifier, + TableMetadataBytes, TableName, TableNamespace, TableType, MAX_COLS_PER_TABLE, }; + use sxt_core::utils::table_treasury_account; + use sxt_core::ByteString; use super::*; @@ -139,9 +154,16 @@ mod benchmarks { T: Config, ::AccountId: Ss58Codec, I: NativeApi, + T::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, { - let (update_table, batch_id, row_data) = + let (mut update_table, batch_id, row_data) = benchmark_expensive_table_and_data::(num_rows, num_cols, commitment_schemes); + update_table.table_type = TableType::Testing(InsertQuorumSize { + public: Some(MAX_SUBMITTERS as u8 - 1), + privileged: None, + }); let (namespace, namespace_ddl, source) = schema_bytes_and_ddl_and_source("BENCHMARK"); pallet_tables::Pallet::::create_namespace( @@ -165,37 +187,39 @@ mod benchmarks { )]) .unwrap(); - let caller: T::AccountId = account("alice", 0, 0); - pallet_permissions::Permissions::::insert(&caller, &permissions); - Indexing::::submit_data( - RawOrigin::Signed(caller).into(), - update_table.ident.clone(), - batch_id.clone(), - row_data.clone(), - ) - .unwrap(); + for i in 0..MAX_SUBMITTERS - 1 { + let submitter: T::AccountId = account("submitter", i, 0); + pallet_permissions::Permissions::::insert(&submitter, &permissions); + pallet_balances::Pallet::::mint_into( + &submitter, + ::ExistentialDeposit::get(), + ) + .unwrap(); + Indexing::::submit_data( + RawOrigin::Signed(submitter).into(), + update_table.ident.clone(), + batch_id.clone(), + row_data.clone(), + ) + .unwrap(); + } - let caller: T::AccountId = account("bob", 0, 0); - pallet_permissions::Permissions::::insert(&caller, &permissions); - Indexing::::submit_data( - RawOrigin::Signed(caller).into(), - update_table.ident.clone(), - batch_id.clone(), - row_data.clone(), - ) - .unwrap(); - let caller: T::AccountId = account("carol", 0, 0); + let caller: T::AccountId = account("caller", 0, 0); pallet_permissions::Permissions::::insert(&caller, &permissions); - Indexing::::submit_data( - RawOrigin::Signed(caller).into(), - update_table.ident.clone(), - batch_id.clone(), - row_data.clone(), + pallet_balances::Pallet::::mint_into( + &caller, + ::ExistentialDeposit::get(), ) .unwrap(); - let caller: T::AccountId = account("dave", 0, 0); - pallet_permissions::Permissions::::insert(&caller, &permissions); + pallet_tables::TableMetadata::::insert( + ByteString::try_from(REFUND_PERCENTAGE_DOMAIN.to_vec()).unwrap(), + &update_table.ident, + TableMetadataBytes::try_from(100u16.encode()).unwrap(), + ); + let treasury = table_treasury_account::(&update_table.ident).unwrap(); + pallet_balances::Pallet::::mint_into(&treasury, T::Balance::max_value() / 2u32.into()) + .unwrap(); (caller, update_table.ident, batch_id, row_data) } diff --git a/pallets/indexing/src/lib.rs b/pallets/indexing/src/lib.rs index a3575086..56ddcf0c 100644 --- a/pallets/indexing/src/lib.rs +++ b/pallets/indexing/src/lib.rs @@ -269,6 +269,9 @@ pub mod pallet { where T: pallet_tables::Config, I: NativeApi, + T::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, { /// Submit an IPC-formatted record batch for a given table. /// @@ -532,9 +535,13 @@ pub mod pallet { where T: Config, I: NativeApi, + T::RuntimeCall: Dispatchable, + ::OnChargeTransaction: + OnChargeTransaction, { let who = ensure_signed(origin.clone())?; + let len = ( as PalletInfoAccess>::index() as u8, &call).encoded_size() as u32; let (table, outer_batch_id, data, block_number) = match call { Call::submit_data { table, @@ -567,14 +574,15 @@ pub mod pallet { &table_insert_quorum, &quorum_scope, )? { + let weight = submit_data_weight::(&data_quorum.table, &data); finalize_quorum::(&data_quorum, data, block_number, who)?; + refund_quorum::(data_quorum, weight, len); } Ok(()) } /// Refunds each quorum submitter the weight and length fee of their call, scaled by [`REFUND_PERCENTAGE_DOMAIN`]. - #[cfg_attr(not(test), expect(dead_code))] pub(crate) fn refund_quorum( quorum: DataQuorum, weight: Weight, diff --git a/pallets/indexing/src/tests.rs b/pallets/indexing/src/tests.rs index fa97f4c9..8f2b3567 100644 --- a/pallets/indexing/src/tests.rs +++ b/pallets/indexing/src/tests.rs @@ -12,13 +12,14 @@ use codec::{Decode, Encode, MaxEncodedLen}; use native_api::Api; use pallet_tables::{CommitmentCreationCmd, UpdateTable}; use polkadot_sdk::frame_support::__private::RuntimeDebug; -use polkadot_sdk::frame_support::dispatch::DispatchResult; +use polkadot_sdk::frame_support::dispatch::{DispatchResult, GetDispatchInfo}; use polkadot_sdk::frame_support::pallet_prelude::TypeInfo; use polkadot_sdk::frame_support::traits::fungible::Mutate; use polkadot_sdk::frame_support::weights::Weight; use polkadot_sdk::frame_support::{assert_err, assert_ok}; use polkadot_sdk::frame_system::ensure_signed; use polkadot_sdk::sp_core::Hasher; +use polkadot_sdk::sp_runtime::traits::Dispatchable; use polkadot_sdk::sp_runtime::BoundedVec; use polkadot_sdk::{frame_system, sp_runtime}; use proof_of_sql_commitment_map::CommitmentSchemeFlags; @@ -2534,6 +2535,167 @@ fn submit_empty_blocks_respects_quorum() { }); } +#[test] +fn refund_is_paid_to_submitter_when_quorum_is_reached() { + for block_number in [None, Some(12345)] { + new_test_ext().execute_with(|| { + System::set_block_number(1); + let (table, create_statement) = sample_table_definition(); + Tables::create_tables( + RuntimeOrigin::root(), + vec![UpdateTable { + ident: table.clone(), + create_statement, + table_type: TableType::Testing(InsertQuorumSize { + public: Some(0), + privileged: None, + }), + commitment: CommitmentCreationCmd::Empty(CommitmentSchemeFlags { + hyper_kzg: true, + dynamic_dory: true, + }), + source: sxt_core::tables::Source::Ethereum, + }] + .try_into() + .unwrap(), + ) + .unwrap(); + set_refund_percentage(&table, 100); + let treasury = table_treasury_account::(&table).unwrap(); + assert_ok!(Balances::mint_into(&treasury, 1_000_000_000_000_000_000)); + let submitter = sp_runtime::AccountId32::new([1; 32]); + pallet_permissions::Permissions::::insert( + submitter.clone(), + PermissionList::try_from(vec![PermissionLevel::IndexingPallet( + IndexingPalletPermission::SubmitDataForPublicQuorum, + )]) + .unwrap(), + ); + let batch_id = BatchId::try_from(b"test_batch".to_vec()).unwrap(); + let origin = RuntimeOrigin::signed(submitter.clone()); + + assert_ok!(match block_number { + None => Indexing::submit_data(origin, table.clone(), batch_id.clone(), row_data()), + Some(n) => Indexing::submit_blockchain_data( + origin, + table.clone(), + batch_id.clone(), + row_data(), + n, + ), + }); + + let refund = Balances::free_balance(&submitter); + assert!(refund > 0, "submitter should have been refunded"); + System::assert_has_event( + Event::::RefundProcessed { + batch_id: build_inner_batch_id::(&batch_id, &table), + table, + refund, + } + .into(), + ); + }); + } +} + +#[test] +fn unrefunded_fee_is_constant_across_batch_sizes() { + let mut expected_unrefunded_fee = None; + let mut per_call_refund = None; + for size in [1, 2, 4, 8] { + let (fee, refund) = new_test_ext().execute_with(|| { + System::set_block_number(1); + let namespace = sample_table_definition().0.namespace; + let tables: Vec<_> = (0..size) + .map(|i| TableIdentifier { + namespace: namespace.clone(), + name: TableName::try_from(format!("TEST_TABLE_{i}").into_bytes()).unwrap(), + }) + .collect(); + Tables::create_tables( + RuntimeOrigin::root(), + (0..size) + .map(|i| UpdateTable { + ident: tables[i].clone(), + create_statement: CreateStatement::try_from( + format!("CREATE TABLE TEST_NAMESPACE.TEST_TABLE_{i} (int_column INT NOT NULL)") + .into_bytes(), + ) + .unwrap(), + table_type: TableType::Testing(InsertQuorumSize { + public: Some(0), + privileged: None, + }), + commitment: CommitmentCreationCmd::Empty(CommitmentSchemeFlags { + hyper_kzg: true, + dynamic_dory: true, + }), + source: sxt_core::tables::Source::Ethereum, + }) + .collect::>() + .try_into() + .unwrap(), + ) + .unwrap(); + for table in &tables { + set_refund_percentage(table, 100); + assert_ok!(Balances::mint_into( + &table_treasury_account::(table).unwrap(), + 1_000_000_000_000_000_000, + )); + } + let submitter = sp_runtime::AccountId32::new([1; 32]); + pallet_permissions::Permissions::::insert( + submitter.clone(), + PermissionList::try_from(vec![PermissionLevel::IndexingPallet( + IndexingPalletPermission::SubmitDataForPublicQuorum, + )]) + .unwrap(), + ); + + let batch = RuntimeCall::Utility(polkadot_sdk::pallet_utility::Call::batch_all { + calls: tables + .into_iter() + .map(|table| { + crate::Call::::submit_data { + table, + batch_id: BatchId::try_from(b"test_batch".to_vec()).unwrap(), + data: row_data(), + } + .into() + }) + .collect(), + }); + let info = batch.get_dispatch_info(); + let post_info = batch + .clone() + .dispatch(RuntimeOrigin::signed(submitter.clone())) + .unwrap(); + let fee = TransactionPayment::compute_actual_fee( + batch.encoded_size() as u32, + &info, + &post_info, + 0, + ) - TransactionPayment::weight_to_fee( + <() as polkadot_sdk::pallet_utility::WeightInfo>::batch_all(size as u32), + ); + + (fee, Balances::free_balance(&submitter)) + }); + assert_eq!( + refund, + *per_call_refund.get_or_insert(refund) * size as u128, + "batch of {size}" + ); + assert_eq!( + *expected_unrefunded_fee.get_or_insert(fee - refund), + fee - refund, + "batch of {size}" + ); + } +} + #[test] fn refund_quorum_pays_each_agreement_its_fee_scaled_by_percentage() { for (percentage, expected_refund) in [(100, 1_001_000), (150, 1_501_500), (200, 2_002_000)] { From a0c2aa4b08d5a3dc2735ffe4f9589834c0581d77 Mon Sep 17 00:00:00 2001 From: Trevor Lovell Date: Fri, 2 Oct 2026 17:13:47 -0600 Subject: [PATCH 9/9] chore: measure indexing weights with quorum refunds A recent change made it so indexers are refunded for contributing to successful inserts. In the worst case, this leads to quite a few extra reads and writes, which are reflected in changes to the benchmarks accordingly. This change measures the weights again after the benchmark changes. --- pallets/indexing/src/weights.rs | 106 ++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/pallets/indexing/src/weights.rs b/pallets/indexing/src/weights.rs index bce551a6..e34302d8 100644 --- a/pallets/indexing/src/weights.rs +++ b/pallets/indexing/src/weights.rs @@ -2,7 +2,7 @@ //! Autogenerated weights for `pallet_indexing` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0 -//! DATE: 2026-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-10-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `trevor-benchmark`, CPU: `AMD EPYC 7763 64-Core Processor` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` @@ -59,20 +59,26 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Commitments::CommitmentStorageMap` (`max_values`: None, `max_size`: Some(45497), added: 47972, mode: `MaxEncodedLen`) /// Storage: `Tables::BlockEnforcement` (r:1 w:0) /// Proof: `Tables::BlockEnforcement` (`max_values`: None, `max_size`: Some(149), added: 2624, mode: `MaxEncodedLen`) + /// Storage: `Tables::TableMetadata` (r:1 w:0) + /// Proof: `Tables::TableMetadata` (`max_values`: None, `max_size`: Some(8424), added: 10899, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:33 w:33) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `c` is `[1, 64]`. /// The range of component `n` is `[0, 16384]`. fn submit_data_quorum_reached_dynamic_dory(c: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1188 + c * (607 ±0)` + // Measured: `6821 + c * (607 ±0)` // Estimated: `276827554 + c * (607 ±0)` - // Minimum execution time: 2_206_770_000 picoseconds. - Weight::from_parts(2_232_157_000, 276827554) - // Standard Error: 25_460_189 - .saturating_add(Weight::from_parts(629_572_780, 0).saturating_mul(c.into())) - // Standard Error: 99_400 - .saturating_add(Weight::from_parts(33_396_949, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 3_706_688_000 picoseconds. + Weight::from_parts(3_802_046_000, 276827554) + // Standard Error: 26_725_519 + .saturating_add(Weight::from_parts(670_991_317, 0).saturating_mul(c.into())) + // Standard Error: 104_340 + .saturating_add(Weight::from_parts(34_006_074, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(46_u64)) + .saturating_add(T::DbWeight::get().writes(36_u64)) .saturating_add(Weight::from_parts(0, 607).saturating_mul(c.into())) } /// Storage: `Tables::TableInsertQuorums` (r:1 w:0) @@ -91,18 +97,24 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Commitments::CommitmentStorageMap` (`max_values`: None, `max_size`: Some(45497), added: 47972, mode: `MaxEncodedLen`) /// Storage: `Tables::BlockEnforcement` (r:1 w:0) /// Proof: `Tables::BlockEnforcement` (`max_values`: None, `max_size`: Some(149), added: 2624, mode: `MaxEncodedLen`) + /// Storage: `Tables::TableMetadata` (r:1 w:0) + /// Proof: `Tables::TableMetadata` (`max_values`: None, `max_size`: Some(8424), added: 10899, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:33 w:33) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `c` is `[1, 64]`. /// The range of component `n` is `[0, 16384]`. fn submit_data_quorum_reached_hyper_kzg(c: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1184 + c * (87 ±0)` + // Measured: `6817 + c * (87 ±0)` // Estimated: `276827554 + c * (87 ±0)` - // Minimum execution time: 913_610_000 picoseconds. - Weight::from_parts(922_727_000, 276827554) - // Standard Error: 64_618 - .saturating_add(Weight::from_parts(33_482_779, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Minimum execution time: 2_450_433_000 picoseconds. + Weight::from_parts(2_601_418_000, 276827554) + // Standard Error: 65_884 + .saturating_add(Weight::from_parts(34_072_128, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(46_u64)) + .saturating_add(T::DbWeight::get().writes(36_u64)) .saturating_add(Weight::from_parts(0, 87).saturating_mul(c.into())) } /// Storage: `Indexing::BlockNumbers` (r:0 w:1) @@ -111,8 +123,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_432_000 picoseconds. - Weight::from_parts(6_693_000, 0) + // Minimum execution time: 7_253_000 picoseconds. + Weight::from_parts(7_604_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Tables::TableInsertQuorums` (r:1 w:0) @@ -135,8 +147,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1110` // Estimated: `276827554` - // Minimum execution time: 113_191_000 picoseconds. - Weight::from_parts(115_686_000, 276827554) + // Minimum execution time: 119_884_000 picoseconds. + Weight::from_parts(122_800_000, 276827554) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -160,20 +172,26 @@ impl WeightInfo for () { /// Proof: `Commitments::CommitmentStorageMap` (`max_values`: None, `max_size`: Some(45497), added: 47972, mode: `MaxEncodedLen`) /// Storage: `Tables::BlockEnforcement` (r:1 w:0) /// Proof: `Tables::BlockEnforcement` (`max_values`: None, `max_size`: Some(149), added: 2624, mode: `MaxEncodedLen`) + /// Storage: `Tables::TableMetadata` (r:1 w:0) + /// Proof: `Tables::TableMetadata` (`max_values`: None, `max_size`: Some(8424), added: 10899, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:33 w:33) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `c` is `[1, 64]`. /// The range of component `n` is `[0, 16384]`. fn submit_data_quorum_reached_dynamic_dory(c: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1188 + c * (607 ±0)` + // Measured: `6821 + c * (607 ±0)` // Estimated: `276827554 + c * (607 ±0)` - // Minimum execution time: 2_206_770_000 picoseconds. - Weight::from_parts(2_232_157_000, 276827554) - // Standard Error: 25_460_189 - .saturating_add(Weight::from_parts(629_572_780, 0).saturating_mul(c.into())) - // Standard Error: 99_400 - .saturating_add(Weight::from_parts(33_396_949, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 3_706_688_000 picoseconds. + Weight::from_parts(3_802_046_000, 276827554) + // Standard Error: 26_725_519 + .saturating_add(Weight::from_parts(670_991_317, 0).saturating_mul(c.into())) + // Standard Error: 104_340 + .saturating_add(Weight::from_parts(34_006_074, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(46_u64)) + .saturating_add(RocksDbWeight::get().writes(36_u64)) .saturating_add(Weight::from_parts(0, 607).saturating_mul(c.into())) } /// Storage: `Tables::TableInsertQuorums` (r:1 w:0) @@ -192,18 +210,24 @@ impl WeightInfo for () { /// Proof: `Commitments::CommitmentStorageMap` (`max_values`: None, `max_size`: Some(45497), added: 47972, mode: `MaxEncodedLen`) /// Storage: `Tables::BlockEnforcement` (r:1 w:0) /// Proof: `Tables::BlockEnforcement` (`max_values`: None, `max_size`: Some(149), added: 2624, mode: `MaxEncodedLen`) + /// Storage: `Tables::TableMetadata` (r:1 w:0) + /// Proof: `Tables::TableMetadata` (`max_values`: None, `max_size`: Some(8424), added: 10899, mode: `MaxEncodedLen`) + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:33 w:33) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `c` is `[1, 64]`. /// The range of component `n` is `[0, 16384]`. fn submit_data_quorum_reached_hyper_kzg(c: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1184 + c * (87 ±0)` + // Measured: `6817 + c * (87 ±0)` // Estimated: `276827554 + c * (87 ±0)` - // Minimum execution time: 913_610_000 picoseconds. - Weight::from_parts(922_727_000, 276827554) - // Standard Error: 64_618 - .saturating_add(Weight::from_parts(33_482_779, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Minimum execution time: 2_450_433_000 picoseconds. + Weight::from_parts(2_601_418_000, 276827554) + // Standard Error: 65_884 + .saturating_add(Weight::from_parts(34_072_128, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(46_u64)) + .saturating_add(RocksDbWeight::get().writes(36_u64)) .saturating_add(Weight::from_parts(0, 87).saturating_mul(c.into())) } /// Storage: `Indexing::BlockNumbers` (r:0 w:1) @@ -212,8 +236,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_432_000 picoseconds. - Weight::from_parts(6_693_000, 0) + // Minimum execution time: 7_253_000 picoseconds. + Weight::from_parts(7_604_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Tables::TableInsertQuorums` (r:1 w:0) @@ -236,8 +260,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1110` // Estimated: `276827554` - // Minimum execution time: 113_191_000 picoseconds. - Weight::from_parts(115_686_000, 276827554) + // Minimum execution time: 119_884_000 picoseconds. + Weight::from_parts(122_800_000, 276827554) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) }