From 048de9002bbe2e91ad6430a59925a10663ff9ed4 Mon Sep 17 00:00:00 2001 From: Sameh Abouelsaad Date: Wed, 18 Feb 2026 18:39:45 +0200 Subject: [PATCH 1/7] Add V3 billing opt-out functionality with admin-only deployment restrictions Implement node-level V3 billing opt-out mechanism allowing farmers to exempt nodes from billing while restricting deployments to authorized twin admins. Add storage maps for opt-out tracking and admin list management. Include billing suppression logic for opted-out nodes in Created state, with zero-cost calculations for both standard and additional fees. --- .../pallet-smart-contract/src/billing.rs | 21 +- .../src/grid_contract.rs | 16 ++ .../pallets/pallet-smart-contract/src/lib.rs | 1 + .../pallet-smart-contract/src/tests.rs | 269 ++++++++++++++++++ .../pallets/pallet-tfgrid/src/benchmarking.rs | 38 +++ .../pallets/pallet-tfgrid/src/lib.rs | 56 ++++ .../pallets/pallet-tfgrid/src/node.rs | 1 + .../pallets/pallet-tfgrid/src/tests.rs | 190 +++++++++++++ .../pallet-tfgrid/src/v3_billing_opt_out.rs | 77 +++++ .../pallets/pallet-tfgrid/src/weights.rs | 33 +++ 10 files changed, 700 insertions(+), 2 deletions(-) create mode 100644 substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs diff --git a/substrate-node/pallets/pallet-smart-contract/src/billing.rs b/substrate-node/pallets/pallet-smart-contract/src/billing.rs index 9178424ee..5f3c5eb1a 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/billing.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/billing.rs @@ -206,6 +206,23 @@ impl Pallet { _ => false, }; + let should_waive_v3_billing = match &contract.contract_type { + types::ContractData::NodeContract(nc) => { + pallet_tfgrid::NodeV3BillingOptOut::::contains_key(nc.node_id) + } + types::ContractData::RentContract(rc) => { + pallet_tfgrid::NodeV3BillingOptOut::::contains_key(rc.node_id) + } + _ => false, + }; + + // For Created contracts on opted-out nodes: early return (mirrors should_waive_payment). + // early return is cleaner and consistent with the should_waive_payment pattern. + // GracePeriod and Deleted fall through: zero new cost + manage_contract_state runs naturally. + if should_waive_v3_billing && matches!(contract.state, types::ContractState::Created) { + return Ok(().into()); + } + if should_waive_payment { log::info!("Waiving rent for contract_id: {:?}", contract.contract_id); Self::deposit_event(Event::RentWaived { @@ -219,7 +236,7 @@ impl Pallet { } // Calculate the due amount - let (standard_amount_due, discount_received) = if should_waive_payment { + let (standard_amount_due, discount_received) = if should_waive_payment || should_waive_v3_billing { (BalanceOf::::zero(), types::DiscountLevel::None) } else { contract @@ -236,7 +253,7 @@ impl Pallet { let additional_amount_due = if let types::ContractData::RentContract(rc) = &contract.contract_type { - if should_waive_payment { + if should_waive_payment || should_waive_v3_billing { BalanceOf::::zero() } else { contract.calculate_extra_fee_cost_tft(rc.node_id, seconds_elapsed) diff --git a/substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs b/substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs index a2fd7222a..a85dbf82f 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs @@ -34,6 +34,14 @@ impl Pallet { Error::::NodeNotAvailableToDeploy ); + // V3 billing opt-out guard: only twin admins can deploy on opted-out nodes + if pallet_tfgrid::NodeV3BillingOptOut::::contains_key(node_id) { + let caller_is_admin = pallet_tfgrid::AllowedTwinAdmins::::get() + .unwrap_or_default() + .contains(&account_id); + ensure!(caller_is_admin, Error::::OnlyTwinAdminCanDeployOnThisNode); + } + let farm = pallet_tfgrid::Farms::::get(node.farm_id).ok_or(Error::::FarmNotExists)?; // A node is dedicated (can only be used under a rent contract) @@ -129,6 +137,14 @@ impl Pallet { Error::::FarmNotExists ); + // V3 billing opt-out guard: only twin admins can deploy on opted-out nodes + if pallet_tfgrid::NodeV3BillingOptOut::::contains_key(node_id) { + let caller_is_admin = pallet_tfgrid::AllowedTwinAdmins::::get() + .unwrap_or_default() + .contains(&account_id); + ensure!(caller_is_admin, Error::::OnlyTwinAdminCanDeployOnThisNode); + } + let active_node_contracts = ActiveNodeContracts::::get(node_id); let farm = pallet_tfgrid::Farms::::get(node.farm_id).ok_or(Error::::FarmNotExists)?; ensure!( diff --git a/substrate-node/pallets/pallet-smart-contract/src/lib.rs b/substrate-node/pallets/pallet-smart-contract/src/lib.rs index e140c900e..14ba20f11 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/lib.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/lib.rs @@ -418,6 +418,7 @@ pub mod pallet { UnauthorizedToSetExtraFee, RewardDistributionError, ContractPaymentStateNotExists, + OnlyTwinAdminCanDeployOnThisNode, } #[pallet::genesis_config] diff --git a/substrate-node/pallets/pallet-smart-contract/src/tests.rs b/substrate-node/pallets/pallet-smart-contract/src/tests.rs index 56b5efdff..c97439f32 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/tests.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/tests.rs @@ -5312,6 +5312,275 @@ fn prepare_solution_provider(origin: AccountId) { )); } +// ------------------------------------------ // +// V3 BILLING OPT-OUT TESTS // +// ------------------------------------------ // + +#[test] +fn test_create_node_contract_on_opted_out_node_non_admin_fails() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_noop!( + SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + ), + Error::::OnlyTwinAdminCanDeployOnThisNode + ); + }); +} + +#[test] +fn test_create_node_contract_on_opted_out_node_admin_succeeds() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_ok!(TfgridModule::add_twin_admin( + RawOrigin::Root.into(), + bob(), + )); + + assert_ok!(SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + )); + }); +} + +#[test] +fn test_create_node_contract_on_normal_node_unaffected() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + )); + }); +} + +#[test] +fn test_create_node_contract_opted_out_empty_admin_list_fails() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_noop!( + SmartContractModule::create_node_contract( + RuntimeOrigin::signed(alice()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + ), + Error::::OnlyTwinAdminCanDeployOnThisNode + ); + }); +} + +#[test] +fn test_admin_removed_cannot_deploy_on_opted_out_node() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_ok!(TfgridModule::add_twin_admin(RawOrigin::Root.into(), bob())); + assert_ok!(TfgridModule::remove_twin_admin(RawOrigin::Root.into(), bob())); + + assert_noop!( + SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + ), + Error::::OnlyTwinAdminCanDeployOnThisNode + ); + }); +} + +#[test] +fn test_create_rent_contract_on_opted_out_node_non_admin_fails() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_dedicated_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_noop!( + SmartContractModule::create_rent_contract( + RuntimeOrigin::signed(charlie()), + node_id, + None, + ), + Error::::OnlyTwinAdminCanDeployOnThisNode + ); + }); +} + +#[test] +fn test_create_rent_contract_on_opted_out_node_admin_succeeds() { + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_dedicated_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_ok!(TfgridModule::add_twin_admin( + RawOrigin::Root.into(), + charlie(), + )); + + assert_ok!(SmartContractModule::create_rent_contract( + RuntimeOrigin::signed(charlie()), + node_id, + None, + )); + }); +} + +#[test] +fn test_billing_suppressed_for_opted_out_node_contract() { + // Note: should_bill_contract returns false for a node contract with no resources/IPs/NU/overdraft, + // so the OCW never submits bill_contract_for_block. We verify billing suppression by directly + // calling bill_contract and checking that balance is unchanged and state stays Created. + new_test_ext().execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::add_twin_admin(RawOrigin::Root.into(), bob())); + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_ok!(SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + )); + let contract_id = 1; + + let balance_before = Balances::free_balance(&bob()); + + // Directly invoke bill_contract (the on-chain extrinsic path) + assert_ok!(SmartContractModule::bill_contract_for_block( + RuntimeOrigin::signed(alice()), + contract_id, + )); + + let balance_after = Balances::free_balance(&bob()); + + // No charge — billing suppressed for opted-out node + assert_eq!(balance_before, balance_after); + + // Contract remains in Created state (not pushed to GracePeriod) + let contract = SmartContractModule::contracts(contract_id).unwrap(); + assert_eq!(contract.state, types::ContractState::Created); + }); +} + +#[test] +fn test_cancel_contract_on_opted_out_node_zero_final_bill() { + let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); + ext.execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + assert_ok!(TfgridModule::add_twin_admin(RawOrigin::Root.into(), bob())); + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_ok!(SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + )); + let contract_id = 1; + + let balance_before = Balances::free_balance(&bob()); + + // Cancel the contract — triggers a final bill_contract call + assert_ok!(SmartContractModule::cancel_contract( + RuntimeOrigin::signed(bob()), + contract_id, + )); + + let balance_after = Balances::free_balance(&bob()); + + // No charge at cancellation either + assert_eq!(balance_before, balance_after); + + // Contract is cleaned up + assert!(SmartContractModule::contracts(contract_id).is_none()); + let _ = pool_state; + }); +} + fn record(event: RuntimeEvent) -> EventRecord { EventRecord { phase: Phase::Initialization, diff --git a/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs b/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs index 1bf13bc87..86d246814 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs @@ -844,6 +844,44 @@ benchmarks! { assert_last_event::(Event::NodeUptimeReported(node_id, now, uptime).into()); } + // opt_out_of_v3_billing() + opt_out_of_v3_billing { + let caller: T::AccountId = whitelisted_caller(); + _prepare_farm_with_node::(caller.clone()); + let node_id = 1; + }: _(RawOrigin::Signed(caller), node_id) + verify { + assert!(TfgridModule::::node_v3_billing_opt_out(node_id).is_some()); + assert_last_event::(Event::NodeV3BillingOptedOut { + node_id, + opted_out_at: TfgridModule::::node_v3_billing_opt_out(node_id).unwrap(), + }.into()); + } + + // add_twin_admin() + add_twin_admin { + let caller: T::AccountId = account("Alice", 0, 0); + }: _(RawOrigin::Root, caller.clone()) + verify { + let admins = TfgridModule::::allowed_twin_admins().unwrap_or_default(); + assert!(admins.contains(&caller)); + assert_last_event::(Event::TwinAdminAdded(caller).into()); + } + + // remove_twin_admin() + remove_twin_admin { + let caller: T::AccountId = account("Alice", 0, 0); + assert_ok!(TfgridModule::::add_twin_admin( + RawOrigin::Root.into(), + caller.clone(), + )); + }: _(RawOrigin::Root, caller.clone()) + verify { + let admins = TfgridModule::::allowed_twin_admins().unwrap_or_default(); + assert!(!admins.contains(&caller)); + assert_last_event::(Event::TwinAdminRemoved(caller).into()); + } + // Calling the `impl_benchmark_test_suite` macro inside the `benchmarks` // block will generate one #[test] function per benchmark impl_benchmark_test_suite!(TfgridModule, crate::mock::new_test_ext(), crate::mock::TestRuntime) diff --git a/substrate-node/pallets/pallet-tfgrid/src/lib.rs b/substrate-node/pallets/pallet-tfgrid/src/lib.rs index 2ecbd4ab1..8de26c97e 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/lib.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/lib.rs @@ -11,6 +11,7 @@ pub mod terms_cond; pub mod twin; pub mod twin_transfer; pub mod types; +pub mod v3_billing_opt_out; pub mod weights; #[cfg(test)] @@ -253,6 +254,18 @@ pub mod pallet { #[pallet::getter(fn zos_version)] pub type ZosVersion = StorageValue<_, Vec, ValueQuery>; + // Keyed by node_id. Present = node has opted out of v3 billing. + #[pallet::storage] + #[pallet::getter(fn node_v3_billing_opt_out)] + pub type NodeV3BillingOptOut = + StorageMap<_, Blake2_128Concat, u32, u64, OptionQuery>; + + // Global list of accounts authorized to deploy on opted-out nodes. + // None = list not initialized (treat as empty = no one allowed). + #[pallet::storage] + #[pallet::getter(fn allowed_twin_admins)] + pub type AllowedTwinAdmins = StorageValue<_, Vec, OptionQuery>; + // This storage map maps a node ID to a power state, they node can modify this state // to indicate that it has shut down or came back alive #[pallet::storage] @@ -469,6 +482,11 @@ pub mod pallet { power_state: PowerState>, }, + // V3 billing opt-out + NodeV3BillingOptedOut { node_id: u32, opted_out_at: u64 }, + TwinAdminAdded(T::AccountId), + TwinAdminRemoved(T::AccountId), + // Twin ownership transfer lifecycle TwinTransferRequested { request_id: u64, @@ -629,6 +647,11 @@ pub mod pallet { TwinTransferRequestNotFound, TwinTransferNewAccountHasTwin, TwinTransferPendingExists, + + // V3 billing opt-out errors + NodeV3BillingOptOutAlreadyEnabled, + AlreadyTwinAdmin, + NotTwinAdmin, } #[pallet::genesis_config] @@ -1323,5 +1346,38 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { Self::_cancel_twin_transfer(origin, request_id) } + + // Farmer opts their node out of v3 billing + #[pallet::call_index(43)] + #[pallet::weight(::WeightInfo::opt_out_of_v3_billing())] + pub fn opt_out_of_v3_billing( + origin: OriginFor, + node_id: u32, + ) -> DispatchResultWithPostInfo { + let account_id = ensure_signed(origin)?; + Self::_opt_out_of_v3_billing(account_id, node_id) + } + + // Council adds an account to the twin admin list (allowed to deploy on opted-out nodes) + #[pallet::call_index(44)] + #[pallet::weight(::WeightInfo::add_twin_admin())] + pub fn add_twin_admin( + origin: OriginFor, + account: T::AccountId, + ) -> DispatchResultWithPostInfo { + T::RestrictedOrigin::ensure_origin(origin)?; + Self::_add_twin_admin(account) + } + + // Council removes an account from the twin admin list + #[pallet::call_index(45)] + #[pallet::weight(::WeightInfo::remove_twin_admin())] + pub fn remove_twin_admin( + origin: OriginFor, + account: T::AccountId, + ) -> DispatchResultWithPostInfo { + T::RestrictedOrigin::ensure_origin(origin)?; + Self::_remove_twin_admin(account) + } } } diff --git a/substrate-node/pallets/pallet-tfgrid/src/node.rs b/substrate-node/pallets/pallet-tfgrid/src/node.rs index c440c97fb..88ad28bfe 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/node.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/node.rs @@ -275,6 +275,7 @@ impl Pallet { T::NodeChanged::node_deleted(&node); Nodes::::remove(node_id); + NodeV3BillingOptOut::::remove(node_id); Self::deposit_event(Event::NodeDeleted(node_id)); diff --git a/substrate-node/pallets/pallet-tfgrid/src/tests.rs b/substrate-node/pallets/pallet-tfgrid/src/tests.rs index 1bb52ef5e..85a3f1226 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/tests.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/tests.rs @@ -2843,6 +2843,196 @@ fn record(event: RuntimeEvent) -> EventRecord { } // Attach given farming policy to farm 1 that contains node 1 +// ------------------------------------ // +// V3 BILLING OPT-OUT TESTS // +// ------------------------------------ // + +#[test] +fn test_opt_out_of_v3_billing_works() { + ExternalityBuilder::build().execute_with(|| { + create_twin(); + create_farm(); + create_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert!(TfgridModule::node_v3_billing_opt_out(node_id).is_some()); + + let our_events = System::events(); + assert!(our_events.iter().any(|e| matches!( + &e.event, + MockEvent::TfgridModule(TfgridEvent::::NodeV3BillingOptedOut { + node_id: 1, + .. + }) + ))); + }); +} + +#[test] +fn test_opt_out_of_v3_billing_not_farmer_fails() { + ExternalityBuilder::build().execute_with(|| { + create_twin(); + create_twin_bob(); + create_farm(); + create_node(); + let node_id = 1; + + assert_noop!( + TfgridModule::opt_out_of_v3_billing(RuntimeOrigin::signed(bob()), node_id), + Error::::NodeUpdateNotAuthorized + ); + }); +} + +#[test] +fn test_opt_out_of_v3_billing_node_not_exists_fails() { + ExternalityBuilder::build().execute_with(|| { + create_twin(); + create_farm(); + + assert_noop!( + TfgridModule::opt_out_of_v3_billing(RuntimeOrigin::signed(alice()), 999), + Error::::NodeNotExists + ); + }); +} + +#[test] +fn test_opt_out_of_v3_billing_already_opted_out_fails() { + ExternalityBuilder::build().execute_with(|| { + create_twin(); + create_farm(); + create_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert_noop!( + TfgridModule::opt_out_of_v3_billing(RuntimeOrigin::signed(alice()), node_id), + Error::::NodeV3BillingOptOutAlreadyEnabled + ); + }); +} + +#[test] +fn test_add_twin_admin_works() { + ExternalityBuilder::build().execute_with(|| { + assert_ok!(TfgridModule::add_twin_admin( + RawOrigin::Root.into(), + alice(), + )); + + let admins = TfgridModule::allowed_twin_admins().unwrap_or_default(); + assert!(admins.contains(&alice())); + + let our_events = System::events(); + assert!(our_events.iter().any(|e| matches!( + &e.event, + MockEvent::TfgridModule(TfgridEvent::::TwinAdminAdded(_)) + ))); + }); +} + +#[test] +fn test_add_twin_admin_not_council_fails() { + ExternalityBuilder::build().execute_with(|| { + assert_noop!( + TfgridModule::add_twin_admin(RuntimeOrigin::signed(alice()), alice()), + sp_runtime::DispatchError::BadOrigin + ); + }); +} + +#[test] +fn test_add_twin_admin_duplicate_fails() { + ExternalityBuilder::build().execute_with(|| { + assert_ok!(TfgridModule::add_twin_admin( + RawOrigin::Root.into(), + alice(), + )); + + assert_noop!( + TfgridModule::add_twin_admin(RawOrigin::Root.into(), alice()), + Error::::AlreadyTwinAdmin + ); + }); +} + +#[test] +fn test_remove_twin_admin_works() { + ExternalityBuilder::build().execute_with(|| { + assert_ok!(TfgridModule::add_twin_admin( + RawOrigin::Root.into(), + alice(), + )); + + assert_ok!(TfgridModule::remove_twin_admin( + RawOrigin::Root.into(), + alice(), + )); + + let admins = TfgridModule::allowed_twin_admins().unwrap_or_default(); + assert!(!admins.contains(&alice())); + + let our_events = System::events(); + assert!(our_events.iter().any(|e| matches!( + &e.event, + MockEvent::TfgridModule(TfgridEvent::::TwinAdminRemoved(_)) + ))); + }); +} + +#[test] +fn test_remove_twin_admin_not_council_fails() { + ExternalityBuilder::build().execute_with(|| { + assert_noop!( + TfgridModule::remove_twin_admin(RuntimeOrigin::signed(alice()), alice()), + sp_runtime::DispatchError::BadOrigin + ); + }); +} + +#[test] +fn test_remove_twin_admin_not_exists_fails() { + ExternalityBuilder::build().execute_with(|| { + assert_noop!( + TfgridModule::remove_twin_admin(RawOrigin::Root.into(), alice()), + Error::::NotTwinAdmin + ); + }); +} + +#[test] +fn test_delete_opted_out_node_cleans_up_storage() { + ExternalityBuilder::build().execute_with(|| { + create_twin(); + create_farm(); + create_node(); + let node_id = 1; + + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + assert!(TfgridModule::node_v3_billing_opt_out(node_id).is_some()); + + assert_ok!(TfgridModule::delete_node( + RuntimeOrigin::signed(alice()), + node_id, + )); + + assert!(TfgridModule::node_v3_billing_opt_out(node_id).is_none()); + }); +} + fn test_attach_farming_policy_flow(farming_policy_id: u32) { create_twin(); create_farm(); diff --git a/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs b/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs new file mode 100644 index 000000000..687887abb --- /dev/null +++ b/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs @@ -0,0 +1,77 @@ +use crate::pallet::{ + AllowedTwinAdmins, Error, Event, Farms, NodeV3BillingOptOut, Nodes, TwinIdByAccountID, +}; +use crate::Config; +use frame_support::{dispatch::DispatchResultWithPostInfo, ensure}; +use sp_runtime::SaturatedConversion; +use sp_std::vec; + +impl crate::Pallet { + pub fn _opt_out_of_v3_billing( + account_id: T::AccountId, + node_id: u32, + ) -> DispatchResultWithPostInfo { + let caller_twin_id = + TwinIdByAccountID::::get(&account_id).ok_or(Error::::TwinNotExists)?; + + let node = Nodes::::get(node_id).ok_or(Error::::NodeNotExists)?; + + let farm = Farms::::get(node.farm_id).ok_or(Error::::FarmNotExists)?; + + ensure!( + caller_twin_id == farm.twin_id, + Error::::NodeUpdateNotAuthorized + ); + + ensure!( + !NodeV3BillingOptOut::::contains_key(node_id), + Error::::NodeV3BillingOptOutAlreadyEnabled + ); + + let now: u64 = + >::get().saturated_into::() / 1000; + + NodeV3BillingOptOut::::insert(node_id, now); + + Self::deposit_event(Event::NodeV3BillingOptedOut { + node_id, + opted_out_at: now, + }); + + Ok(().into()) + } + + pub fn _add_twin_admin(account: T::AccountId) -> DispatchResultWithPostInfo { + match AllowedTwinAdmins::::get() { + Some(mut admins) => { + let location = admins + .binary_search(&account) + .err() + .ok_or(Error::::AlreadyTwinAdmin)?; + admins.insert(location, account.clone()); + AllowedTwinAdmins::::put(admins); + } + None => { + AllowedTwinAdmins::::put(vec![account.clone()]); + } + } + + Self::deposit_event(Event::TwinAdminAdded(account)); + + Ok(().into()) + } + + pub fn _remove_twin_admin(account: T::AccountId) -> DispatchResultWithPostInfo { + let mut admins = AllowedTwinAdmins::::get().ok_or(Error::::NotTwinAdmin)?; + let location = admins + .binary_search(&account) + .ok() + .ok_or(Error::::NotTwinAdmin)?; + admins.remove(location); + AllowedTwinAdmins::::put(admins); + + Self::deposit_event(Event::TwinAdminRemoved(account)); + + Ok(().into()) + } +} diff --git a/substrate-node/pallets/pallet-tfgrid/src/weights.rs b/substrate-node/pallets/pallet-tfgrid/src/weights.rs index e9d1ffa27..782a8aa3b 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/weights.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/weights.rs @@ -68,6 +68,9 @@ pub trait WeightInfo { fn change_power_target() -> Weight; fn bond_twin_account() -> Weight; fn report_uptime_v2() -> Weight; + fn opt_out_of_v3_billing() -> Weight; + fn add_twin_admin() -> Weight; + fn remove_twin_admin() -> Weight; } /// Weights for pallet_tfgrid using the Substrate node and recommended hardware. @@ -419,6 +422,21 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + fn opt_out_of_v3_billing() -> Weight { + Weight::from_parts(20_000_000, 0) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn add_twin_admin() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn remove_twin_admin() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Nodes` (r:1 w:1) @@ -952,6 +970,21 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + fn opt_out_of_v3_billing() -> Weight { + Weight::from_parts(20_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + fn add_twin_admin() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + fn remove_twin_admin() -> Weight { + Weight::from_parts(10_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Nodes` (r:1 w:1) From c2fafeaa275b18159957c25ed4d5a4320c9b3461 Mon Sep 17 00:00:00 2001 From: Sameh Abouelsaad Date: Wed, 18 Feb 2026 22:28:54 +0200 Subject: [PATCH 2/7] Refactor billing waiver variable names for clarity --- .../pallets/pallet-smart-contract/src/billing.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/substrate-node/pallets/pallet-smart-contract/src/billing.rs b/substrate-node/pallets/pallet-smart-contract/src/billing.rs index 5f3c5eb1a..28be9ad94 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/billing.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/billing.rs @@ -198,7 +198,7 @@ impl Pallet { let seconds_elapsed = now.defensive_saturating_sub(contract_payment_state.last_updated_seconds); - let should_waive_payment = match &contract.contract_type { + let should_waive_standby_rent = match &contract.contract_type { types::ContractData::RentContract(rc) => { let node_power = pallet_tfgrid::NodePower::::get(rc.node_id); node_power.is_standby() @@ -206,7 +206,7 @@ impl Pallet { _ => false, }; - let should_waive_v3_billing = match &contract.contract_type { + let should_waive_migration_billing = match &contract.contract_type { types::ContractData::NodeContract(nc) => { pallet_tfgrid::NodeV3BillingOptOut::::contains_key(nc.node_id) } @@ -216,14 +216,14 @@ impl Pallet { _ => false, }; - // For Created contracts on opted-out nodes: early return (mirrors should_waive_payment). - // early return is cleaner and consistent with the should_waive_payment pattern. + // For Created contracts on opted-out nodes: early return (mirrors should_waive_standby_rent). + // early return is cleaner and consistent with the should_waive_standby_rent pattern. // GracePeriod and Deleted fall through: zero new cost + manage_contract_state runs naturally. - if should_waive_v3_billing && matches!(contract.state, types::ContractState::Created) { + if should_waive_migration_billing && matches!(contract.state, types::ContractState::Created) { return Ok(().into()); } - if should_waive_payment { + if should_waive_standby_rent { log::info!("Waiving rent for contract_id: {:?}", contract.contract_id); Self::deposit_event(Event::RentWaived { contract_id: contract.contract_id, @@ -236,7 +236,7 @@ impl Pallet { } // Calculate the due amount - let (standard_amount_due, discount_received) = if should_waive_payment || should_waive_v3_billing { + let (standard_amount_due, discount_received) = if should_waive_standby_rent || should_waive_migration_billing { (BalanceOf::::zero(), types::DiscountLevel::None) } else { contract @@ -253,7 +253,7 @@ impl Pallet { let additional_amount_due = if let types::ContractData::RentContract(rc) = &contract.contract_type { - if should_waive_payment || should_waive_v3_billing { + if should_waive_standby_rent || should_waive_migration_billing { BalanceOf::::zero() } else { contract.calculate_extra_fee_cost_tft(rc.node_id, seconds_elapsed) From befa5e1e63a0b2cb84876debf8ee8543f6bd534b Mon Sep 17 00:00:00 2001 From: Sameh Abouelsaad Date: Wed, 18 Feb 2026 23:33:17 +0200 Subject: [PATCH 3/7] test: Improve V3 billing opt-out test coverage --- .../pallet-smart-contract/src/tests.rs | 142 +++++++++++++----- 1 file changed, 108 insertions(+), 34 deletions(-) diff --git a/substrate-node/pallets/pallet-smart-contract/src/tests.rs b/substrate-node/pallets/pallet-smart-contract/src/tests.rs index c97439f32..1ca11c5bc 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/tests.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/tests.rs @@ -5371,25 +5371,10 @@ fn test_create_node_contract_on_opted_out_node_admin_succeeds() { } #[test] -fn test_create_node_contract_on_normal_node_unaffected() { - new_test_ext().execute_with(|| { - run_to_block(1, None); - prepare_farm_and_node(); - let node_id = 1; - - assert_ok!(SmartContractModule::create_node_contract( - RuntimeOrigin::signed(bob()), - node_id, - generate_deployment_hash(), - get_deployment_data(), - 0, - None, - )); - }); -} - -#[test] -fn test_create_node_contract_opted_out_empty_admin_list_fails() { +fn test_create_node_contract_opted_out_farmer_cannot_self_deploy() { + // The farmer who opted out is NOT automatically an admin — they must be explicitly added. + // This is a distinct case from test_create_node_contract_on_opted_out_node_non_admin_fails + // which uses an unrelated account (bob). Here the farmer (alice) tries to deploy on their own node. new_test_ext().execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); @@ -5493,10 +5478,8 @@ fn test_create_rent_contract_on_opted_out_node_admin_succeeds() { #[test] fn test_billing_suppressed_for_opted_out_node_contract() { - // Note: should_bill_contract returns false for a node contract with no resources/IPs/NU/overdraft, - // so the OCW never submits bill_contract_for_block. We verify billing suppression by directly - // calling bill_contract and checking that balance is unchanged and state stays Created. - new_test_ext().execute_with(|| { + let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); + ext.execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); let node_id = 1; @@ -5518,17 +5501,19 @@ fn test_billing_suppressed_for_opted_out_node_contract() { )); let contract_id = 1; + push_contract_resources_used(contract_id); + let balance_before = Balances::free_balance(&bob()); - // Directly invoke bill_contract (the on-chain extrinsic path) - assert_ok!(SmartContractModule::bill_contract_for_block( - RuntimeOrigin::signed(alice()), - contract_id, - )); + // OCW fires at block 11 (billing cycle), but cost is zeroed by should_waive_migration_billing + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 11); + run_to_block(11, Some(&mut pool_state)); let balance_after = Balances::free_balance(&bob()); - // No charge — billing suppressed for opted-out node + // No charge despite real resource usage — billing suppressed for opted-out node assert_eq!(balance_before, balance_after); // Contract remains in Created state (not pushed to GracePeriod) @@ -5539,8 +5524,7 @@ fn test_billing_suppressed_for_opted_out_node_contract() { #[test] fn test_cancel_contract_on_opted_out_node_zero_final_bill() { - let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); - ext.execute_with(|| { + new_test_ext().execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); let node_id = 1; @@ -5562,9 +5546,11 @@ fn test_cancel_contract_on_opted_out_node_zero_final_bill() { )); let contract_id = 1; + push_contract_resources_used(contract_id); + let balance_before = Balances::free_balance(&bob()); - // Cancel the contract — triggers a final bill_contract call + // Cancel triggers bill_contract inline (no OCW) with state=Deleted assert_ok!(SmartContractModule::cancel_contract( RuntimeOrigin::signed(bob()), contract_id, @@ -5572,12 +5558,100 @@ fn test_cancel_contract_on_opted_out_node_zero_final_bill() { let balance_after = Balances::free_balance(&bob()); - // No charge at cancellation either + // No charge despite real resource usage — migration billing suppressed at cancellation too assert_eq!(balance_before, balance_after); // Contract is cleaned up assert!(SmartContractModule::contracts(contract_id).is_none()); - let _ = pool_state; + }); +} + +#[test] +fn test_grace_period_contract_restored_and_billing_free_after_opt_out() { + // Scenario: + // 1. charlie deploys on a normal node, runs out of funds → GracePeriod + // 2. Farmer opts out of v3 billing while contract is in GracePeriod + // 3. charlie tops up → next billing cycle restores contract to Created + // 4. Subsequent billing cycle: resources are present but cost is zero (migration window) + let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); + ext.execute_with(|| { + run_to_block(1, None); + prepare_farm_and_node(); + let node_id = 1; + + TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); + + // charlie (low balance) deploys — node is NOT yet opted out + assert_ok!(TfgridModule::add_twin_admin(RawOrigin::Root.into(), charlie())); + assert_ok!(SmartContractModule::create_node_contract( + RuntimeOrigin::signed(charlie()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 0, + None, + )); + let contract_id = 1; + + push_contract_resources_used(contract_id); + + // Cycle 1: charlie can pay + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 11); + run_to_block(11, Some(&mut pool_state)); + + // Cycle 2: charlie runs out of funds → GracePeriod + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 21); + run_to_block(21, Some(&mut pool_state)); + + let contract = SmartContractModule::contracts(contract_id).unwrap(); + assert_eq!(contract.state, types::ContractState::GracePeriod(21)); + + // Farmer opts out while contract is in GracePeriod + assert_ok!(TfgridModule::opt_out_of_v3_billing( + RuntimeOrigin::signed(alice()), + node_id, + )); + + // Cycle 3: charlie still can't pay, stays in GracePeriod + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 31); + run_to_block(31, Some(&mut pool_state)); + + let contract = SmartContractModule::contracts(contract_id).unwrap(); + assert_eq!(contract.state, types::ContractState::GracePeriod(21)); + + // charlie tops up to cover the pre-opt-out overdraft + Balances::transfer(RuntimeOrigin::signed(bob()), charlie(), 100000000).unwrap(); + + // Cycle 4: sufficient funds → contract restored to Created + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 41); + run_to_block(41, Some(&mut pool_state)); + + let contract = SmartContractModule::contracts(contract_id).unwrap(); + assert_eq!(contract.state, types::ContractState::Created); + + // Cycle 5: contract is Created on opted-out node with resources — billing must be free + let balance_before = Balances::free_balance(&charlie()); + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 51); + run_to_block(51, Some(&mut pool_state)); + + let balance_after = Balances::free_balance(&charlie()); + + // No charge — migration window active + assert_eq!(balance_before, balance_after); + + // Contract stays Created (not pushed back to GracePeriod despite no payment) + let contract = SmartContractModule::contracts(contract_id).unwrap(); + assert_eq!(contract.state, types::ContractState::Created); }); } From 9620380cb570580ef09b5b9a8444e57d35fc1fa1 Mon Sep 17 00:00:00 2001 From: Sameh Abouelsaad Date: Wed, 18 Feb 2026 23:45:10 +0200 Subject: [PATCH 4/7] docs: Add ADR for V3 billing opt-out mechanism --- docs/architecture/0025-v3-billing-opt-out.md | 66 ++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/architecture/0025-v3-billing-opt-out.md diff --git a/docs/architecture/0025-v3-billing-opt-out.md b/docs/architecture/0025-v3-billing-opt-out.md new file mode 100644 index 000000000..3fa3dd3cd --- /dev/null +++ b/docs/architecture/0025-v3-billing-opt-out.md @@ -0,0 +1,66 @@ +# 25. V3 Billing Opt-Out for Node Migration + +Date: 2026-02-18 + +## Status + +Accepted + +## Context + +During the migration from v3 to Mycelium, farmers need a way to signal that their nodes are entering a migration window. Existing workloads on these nodes should not be billed during this period, as the node is transitioning infrastructure. + +## Decision + +### New Storage Items (pallet-tfgrid) + +- **`NodeV3BillingOptOut`**: A `StorageMap` tracking which nodes have opted out. Presence in this map is the sole indicator of opt-out status. No storage migration is required as this is an additive change. +- **`AllowedTwinAdmins`**: A `StorageValue>` listing accounts authorized to deploy on opted-out nodes. + +### New Extrinsics (pallet-tfgrid) + +| Extrinsic | Origin | Call Index | +|---|---|---| +| `opt_out_of_v3_billing(node_id)` | Farmer (signed) | 43 | +| `add_twin_admin(account)` | Council (`RestrictedOrigin`) | 44 | +| `remove_twin_admin(account)` | Council (`RestrictedOrigin`) | 45 | + +Opt-out is one-way and permanent — there is no opt-back-in extrinsic. The `NodeV3BillingOptOut` entry is cleaned up automatically when the node is deleted. + +### Deployment Guards (pallet-smart-contract) + +`_create_node_contract` and `_create_rent_contract` both check `NodeV3BillingOptOut` before allowing deployment. If the target node has opted out, the caller's `AccountId` must be present in `AllowedTwinAdmins`, otherwise the call fails with `OnlyTwinAdminCanDeployOnThisNode`. + +### Billing Suppression (pallet-smart-contract) + +In `bill_contract`, a `should_waive_migration_billing` flag is computed by checking `NodeV3BillingOptOut` for the contract's node. When true: + +- **`Created` state**: early return, no billing work performed. +- **`GracePeriod` state**: cost is zeroed; `manage_contract_state` runs normally, allowing the contract to be restored to `Created` once the user tops up to cover pre-opt-out overdraft. +- **`Deleted` state**: cost is zeroed; cleanup proceeds normally. + +This is distinct from `should_waive_standby_rent` (standby power state, rent contracts only, emits `RentWaived`). The migration billing waiver is silent — no event is emitted because no billing is expected after opt-out. + +### New Events (pallet-tfgrid) + +- `NodeV3BillingOptedOut { node_id, opted_out_at }` — emitted on successful opt-out. +- `TwinAdminAdded(AccountId)` — emitted when an admin is added. +- `TwinAdminRemoved(AccountId)` — emitted when an admin is removed. + +### New Errors + +**pallet-smart-contract** + +- `OnlyTwinAdminCanDeployOnThisNode` — returned when a non-admin attempts to deploy on an opted-out node. + +**pallet-tfgrid** + +- `NodeV3BillingOptOutAlreadyEnabled` — returned when `opt_out_of_v3_billing` is called on a node that has already opted out. +- `AlreadyTwinAdmin` — returned when `add_twin_admin` is called for an account already in the admin list. +- `NotTwinAdmin` — returned when `remove_twin_admin` is called for an account not in the admin list, or when the list is empty. + +## Consequences + +- **No storage migration**: all new storage items are additive. +- **Free migration window**: existing workloads on opted-out nodes accumulate no new charges. Users with pre-existing overdraft (contracts in `GracePeriod`) can still top up to restore their workloads, after which subsequent billing cycles are free. +- **Access control**: only council-approved twin admins can deploy new workloads on opted-out nodes. From 0e211355a2fd737cd7cce5dc897574858883c283 Mon Sep 17 00:00:00 2001 From: Sameh Abouelsaad Date: Thu, 19 Feb 2026 00:10:35 +0200 Subject: [PATCH 5/7] feat: Add V3 billing opt-out and twin admin management to Go client Implement client methods for V3 billing opt-out functionality including OptOutOfV3Billing, AddTwinAdmin, RemoveTwinAdmin, GetAllowedTwinAdmins, and IsNodeOptedOutOfV3Billing. Add corresponding event types NodeV3BillingOptedOut, TwinAdminAdded, and TwinAdminRemoved. Include comprehensive unit tests and update error definitions for new tfgrid and smart contract module errors. --- clients/tfchain-client-go/events.go | 22 +++++ clients/tfchain-client-go/node.go | 118 +++++++++++++++++++++++++ clients/tfchain-client-go/node_test.go | 48 ++++++++++ clients/tfchain-client-go/utils.go | 7 ++ 4 files changed, 195 insertions(+) diff --git a/clients/tfchain-client-go/events.go b/clients/tfchain-client-go/events.go index 70f462826..8f1b7210b 100644 --- a/clients/tfchain-client-go/events.go +++ b/clients/tfchain-client-go/events.go @@ -331,6 +331,25 @@ type ZosVersionUpdated struct { Topics []types.Hash } +type NodeV3BillingOptedOut struct { + Phase types.Phase + NodeID types.U32 `json:"node_id"` + OptedOutAt types.U64 `json:"opted_out_at"` + Topics []types.Hash +} + +type TwinAdminAdded struct { + Phase types.Phase + Account AccountID `json:"account_id"` + Topics []types.Hash +} + +type TwinAdminRemoved struct { + Phase types.Phase + Account AccountID `json:"account_id"` + Topics []types.Hash +} + type EventSchedulerCallUnavailable struct { Phase types.Phase Task types.TaskAddress @@ -467,6 +486,9 @@ type EventRecords struct { TfgridModule_FarmingPolicySet []FarmingPolicySet //nolint:stylecheck,golint TfgridModule_FarmCertificationSet []FarmCertificationSet //nolint:stylecheck,golint TfgridModule_ZosVersionUpdated []ZosVersionUpdated //nolint:stylecheck,golint + TfgridModule_NodeV3BillingOptedOut []NodeV3BillingOptedOut //nolint:stylecheck,golint + TfgridModule_TwinAdminAdded []TwinAdminAdded //nolint:stylecheck,golint + TfgridModule_TwinAdminRemoved []TwinAdminRemoved //nolint:stylecheck,golint // burn module events BurningModule_BurnTransactionCreated []BurnTransactionCreated //nolint:stylecheck,golint diff --git a/clients/tfchain-client-go/node.go b/clients/tfchain-client-go/node.go index 6eade3661..96ad8ad91 100644 --- a/clients/tfchain-client-go/node.go +++ b/clients/tfchain-client-go/node.go @@ -805,6 +805,124 @@ func (s *Substrate) GetDedicatedNodePrice(nodeID uint32) (uint64, error) { return uint64(price), nil } +// OptOutOfV3Billing opts a node out of the v3 billing system, opening a free migration window. +// Only the farmer who owns the node can call this. +func (s *Substrate) OptOutOfV3Billing(identity Identity, nodeID uint32) (hash types.Hash, err error) { + cl, meta, err := s.GetClient() + if err != nil { + return hash, err + } + + c, err := types.NewCall(meta, "TfgridModule.opt_out_of_v3_billing", nodeID) + if err != nil { + return hash, errors.Wrap(err, "failed to create call") + } + + callResponse, err := s.Call(cl, meta, identity, c) + if err != nil { + return hash, errors.Wrap(err, "failed to opt out of v3 billing") + } + + return callResponse.Hash, nil +} + +// AddTwinAdmin adds an account to the list of twin admins allowed to deploy on opted-out nodes. +// Requires council (restricted) origin. +func (s *Substrate) AddTwinAdmin(identity Identity, account AccountID) (hash types.Hash, err error) { + cl, meta, err := s.GetClient() + if err != nil { + return hash, err + } + + c, err := types.NewCall(meta, "TfgridModule.add_twin_admin", account) + if err != nil { + return hash, errors.Wrap(err, "failed to create call") + } + + callResponse, err := s.Call(cl, meta, identity, c) + if err != nil { + return hash, errors.Wrap(err, "failed to add twin admin") + } + + return callResponse.Hash, nil +} + +// RemoveTwinAdmin removes an account from the list of twin admins allowed to deploy on opted-out nodes. +// Requires council (restricted) origin. +func (s *Substrate) RemoveTwinAdmin(identity Identity, account AccountID) (hash types.Hash, err error) { + cl, meta, err := s.GetClient() + if err != nil { + return hash, err + } + + c, err := types.NewCall(meta, "TfgridModule.remove_twin_admin", account) + if err != nil { + return hash, errors.Wrap(err, "failed to create call") + } + + callResponse, err := s.Call(cl, meta, identity, c) + if err != nil { + return hash, errors.Wrap(err, "failed to remove twin admin") + } + + return callResponse.Hash, nil +} + +// GetAllowedTwinAdmins returns the list of accounts allowed to deploy on opted-out nodes. +// Returns an empty slice if no admins have been configured. +func (s *Substrate) GetAllowedTwinAdmins() ([]AccountID, error) { + cl, meta, err := s.GetClient() + if err != nil { + return nil, err + } + + key, err := types.CreateStorageKey(meta, "TfgridModule", "AllowedTwinAdmins") + if err != nil { + return nil, errors.Wrap(err, "failed to create substrate query key") + } + + raw, err := cl.RPC.State.GetStorageRawLatest(key) + if err != nil { + return nil, errors.Wrap(err, "failed to lookup allowed twin admins") + } + + if len(*raw) == 0 { + return []AccountID{}, nil + } + + var admins []AccountID + if err := Decode(*raw, &admins); err != nil { + return nil, errors.Wrap(err, "failed to decode allowed twin admins") + } + + return admins, nil +} + +// IsNodeOptedOutOfV3Billing returns true if the node has opted out of v3 billing. +func (s *Substrate) IsNodeOptedOutOfV3Billing(nodeID uint32) (bool, error) { + cl, meta, err := s.GetClient() + if err != nil { + return false, err + } + + bytes, err := Encode(nodeID) + if err != nil { + return false, errors.Wrap(err, "substrate: encoding error building query arguments") + } + + key, err := types.CreateStorageKey(meta, "TfgridModule", "NodeV3BillingOptOut", bytes) + if err != nil { + return false, errors.Wrap(err, "failed to create substrate query key") + } + + raw, err := cl.RPC.State.GetStorageRawLatest(key) + if err != nil { + return false, errors.Wrap(err, "failed to lookup node v3 billing opt-out") + } + + return len(*raw) > 0, nil +} + // SetNodeCertificate sets the node certificate type func (s *Substrate) SetNodeCertificate(identity Identity, id uint32, cert NodeCertification) error { cl, meta, err := s.GetClient() diff --git a/clients/tfchain-client-go/node_test.go b/clients/tfchain-client-go/node_test.go index 5bb185764..d59b81acf 100644 --- a/clients/tfchain-client-go/node_test.go +++ b/clients/tfchain-client-go/node_test.go @@ -67,6 +67,54 @@ func TestSetDedicatedNodePrice(t *testing.T) { require.Equal(t, uint64(price), priceSet) } +func TestOptOutOfV3Billing(t *testing.T) { + cl := startLocalConnection(t) + defer cl.Close() + + // Bob is the farmer + identity, err := NewIdentityFromSr25519Phrase(BobMnemonics) + require.NoError(t, err) + + farmID, twinID := assertCreateFarm(t, cl) + nodeID := assertCreateNode(t, cl, farmID, twinID, identity) + + _, err = cl.OptOutOfV3Billing(identity, nodeID) + // NodeV3BillingOptOutAlreadyEnabled is acceptable on re-runs (opt-out is permanent) + if err != nil { + require.EqualError(t, err, "NodeV3BillingOptOutAlreadyEnabled") + } + + optedOut, err := cl.IsNodeOptedOutOfV3Billing(nodeID) + require.NoError(t, err) + require.True(t, optedOut) +} + +func TestGetAllowedTwinAdmins(t *testing.T) { + cl := startLocalConnection(t) + defer cl.Close() + + rootIdentity, err := NewIdentityFromSr25519Phrase(AliceMnemonics) + require.NoError(t, err) + + bobAccount, err := FromAddress(BobAddress) + require.NoError(t, err) + + // Ensure Bob is in the list + _, err = cl.AddTwinAdmin(rootIdentity, bobAccount) + require.NoError(t, err) + admins, err := cl.GetAllowedTwinAdmins() + require.NoError(t, err) + require.Contains(t, admins, bobAccount) + + // Clean up + _, err = cl.RemoveTwinAdmin(rootIdentity, bobAccount) + require.NoError(t, err) + + admins, err = cl.GetAllowedTwinAdmins() + require.NoError(t, err) + require.NotContains(t, admins, bobAccount) +} + func TestUptimeReport(t *testing.T) { cl := startLocalConnection(t) defer cl.Close() diff --git a/clients/tfchain-client-go/utils.go b/clients/tfchain-client-go/utils.go index 9d23d7bc9..d5e7c0163 100644 --- a/clients/tfchain-client-go/utils.go +++ b/clients/tfchain-client-go/utils.go @@ -129,6 +129,7 @@ var smartContractModuleErrors = []string{ "UnauthorizedToSetExtraFee", "RewardDistributionError", "ContractPaymentStateNotExists", + "OnlyTwinAdminCanDeployOnThisNode", } // https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-tfgrid/src/lib.rs#L442 @@ -249,6 +250,12 @@ var tfgridModuleErrors = []string{ "InvalidRelayAddress", "InvalidTimestampHint", "InvalidStorageInput", + "TwinTransferRequestNotFound", + "TwinTransferNewAccountHasTwin", + "TwinTransferPendingExists", + "NodeV3BillingOptOutAlreadyEnabled", + "AlreadyTwinAdmin", + "NotTwinAdmin", } // https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-tft-bridge/src/lib.rs#L152 From d37f6fc418c01653da5d1afc16143c0c59050e3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 19 Feb 2026 11:43:05 +0000 Subject: [PATCH 6/7] chore: update benchmark `weights.rs` file for all pallets --- .../pallets/pallet-burning/src/weights.rs | 12 +- .../pallets/pallet-dao/src/weights.rs | 36 +- .../pallets/pallet-kvstore/src/weights.rs | 20 +- .../pallet-smart-contract/src/weights.rs | 236 +++++----- .../pallets/pallet-tfgrid/src/weights.rs | 404 ++++++++++-------- .../pallets/pallet-tft-bridge/src/weights.rs | 92 ++-- .../pallets/pallet-tft-price/src/weights.rs | 28 +- .../pallets/pallet-validator/src/weights.rs | 52 +-- .../substrate-validator-set/src/weights.rs | 28 +- 9 files changed, 494 insertions(+), 414 deletions(-) diff --git a/substrate-node/pallets/pallet-burning/src/weights.rs b/substrate-node/pallets/pallet-burning/src/weights.rs index c319c57ae..3e8a3f87c 100644 --- a/substrate-node/pallets/pallet-burning/src/weights.rs +++ b/substrate-node/pallets/pallet-burning/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_burning //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -45,8 +45,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 26_060_000 picoseconds. - Weight::from_parts(26_561_000, 1594) + // Minimum execution time: 54_457_000 picoseconds. + Weight::from_parts(93_148_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -60,8 +60,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 26_060_000 picoseconds. - Weight::from_parts(26_561_000, 1594) + // Minimum execution time: 54_457_000 picoseconds. + Weight::from_parts(93_148_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate-node/pallets/pallet-dao/src/weights.rs b/substrate-node/pallets/pallet-dao/src/weights.rs index b97ec0112..dcfef11bb 100644 --- a/substrate-node/pallets/pallet-dao/src/weights.rs +++ b/substrate-node/pallets/pallet-dao/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_dao //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -58,8 +58,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `208` // Estimated: `4687` - // Minimum execution time: 18_274_000 picoseconds. - Weight::from_parts(18_706_000, 4687) + // Minimum execution time: 38_004_000 picoseconds. + Weight::from_parts(40_173_000, 4687) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -77,8 +77,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `979` // Estimated: `4444` - // Minimum execution time: 24_997_000 picoseconds. - Weight::from_parts(25_498_000, 4444) + // Minimum execution time: 48_203_000 picoseconds. + Weight::from_parts(50_745_000, 4444) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -92,8 +92,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `487` // Estimated: `4687` - // Minimum execution time: 17_904_000 picoseconds. - Weight::from_parts(18_395_000, 4687) + // Minimum execution time: 34_237_000 picoseconds. + Weight::from_parts(48_378_000, 4687) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -111,8 +111,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `521` // Estimated: `4687` - // Minimum execution time: 24_947_000 picoseconds. - Weight::from_parts(26_390_000, 4687) + // Minimum execution time: 50_644_000 picoseconds. + Weight::from_parts(57_493_000, 4687) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -136,8 +136,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `208` // Estimated: `4687` - // Minimum execution time: 18_274_000 picoseconds. - Weight::from_parts(18_706_000, 4687) + // Minimum execution time: 38_004_000 picoseconds. + Weight::from_parts(40_173_000, 4687) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -155,8 +155,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `979` // Estimated: `4444` - // Minimum execution time: 24_997_000 picoseconds. - Weight::from_parts(25_498_000, 4444) + // Minimum execution time: 48_203_000 picoseconds. + Weight::from_parts(50_745_000, 4444) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -170,8 +170,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `487` // Estimated: `4687` - // Minimum execution time: 17_904_000 picoseconds. - Weight::from_parts(18_395_000, 4687) + // Minimum execution time: 34_237_000 picoseconds. + Weight::from_parts(48_378_000, 4687) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -189,8 +189,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `521` // Estimated: `4687` - // Minimum execution time: 24_947_000 picoseconds. - Weight::from_parts(26_390_000, 4687) + // Minimum execution time: 50_644_000 picoseconds. + Weight::from_parts(57_493_000, 4687) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate-node/pallets/pallet-kvstore/src/weights.rs b/substrate-node/pallets/pallet-kvstore/src/weights.rs index df9f5ae3f..96a3b72a6 100644 --- a/substrate-node/pallets/pallet-kvstore/src/weights.rs +++ b/substrate-node/pallets/pallet-kvstore/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_kvstore //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -46,8 +46,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_833_000 picoseconds. - Weight::from_parts(7_104_000, 0) + // Minimum execution time: 23_608_000 picoseconds. + Weight::from_parts(28_283_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TFKVStore::TFKVStore` (r:1 w:1) @@ -56,8 +56,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3611` - // Minimum execution time: 11_963_000 picoseconds. - Weight::from_parts(12_283_000, 3611) + // Minimum execution time: 23_301_000 picoseconds. + Weight::from_parts(24_584_000, 3611) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -71,8 +71,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_833_000 picoseconds. - Weight::from_parts(7_104_000, 0) + // Minimum execution time: 23_608_000 picoseconds. + Weight::from_parts(28_283_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TFKVStore::TFKVStore` (r:1 w:1) @@ -81,8 +81,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `146` // Estimated: `3611` - // Minimum execution time: 11_963_000 picoseconds. - Weight::from_parts(12_283_000, 3611) + // Minimum execution time: 23_301_000 picoseconds. + Weight::from_parts(24_584_000, 3611) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate-node/pallets/pallet-smart-contract/src/weights.rs b/substrate-node/pallets/pallet-smart-contract/src/weights.rs index fc3e7c640..7ec5ae660 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/weights.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_smart_contract //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -67,6 +67,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::NodePower` (r:1 w:0) /// Proof: `TfgridModule::NodePower` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Farms` (r:1 w:1) /// Proof: `TfgridModule::Farms` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::DedicatedNodesExtraFee` (r:1 w:0) @@ -95,9 +97,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `868` // Estimated: `4333` - // Minimum execution time: 47_449_000 picoseconds. - Weight::from_parts(48_522_000, 4333) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Minimum execution time: 125_637_000 picoseconds. + Weight::from_parts(158_842_000, 4333) + .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) @@ -110,8 +112,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `869` // Estimated: `4334` - // Minimum execution time: 22_553_000 picoseconds. - Weight::from_parts(23_053_000, 4334) + // Minimum execution time: 45_372_000 picoseconds. + Weight::from_parts(73_961_000, 4334) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -133,6 +135,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TfgridModule::TwinBoundedAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveRentContractForNode` (r:1 w:0) /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -149,9 +153,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `7590` - // Minimum execution time: 73_609_000 picoseconds. - Weight::from_parts(74_771_000, 7590) - .saturating_add(T::DbWeight::get().reads(13_u64)) + // Minimum execution time: 156_863_000 picoseconds. + Weight::from_parts(256_304_000, 7590) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -174,8 +178,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3805` - // Minimum execution time: 24_006_000 picoseconds. - Weight::from_parts(24_456_000, 3805) + // Minimum execution time: 71_124_000 picoseconds. + Weight::from_parts(77_955_000, 3805) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -201,8 +205,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `949` // Estimated: `4414` - // Minimum execution time: 50_195_000 picoseconds. - Weight::from_parts(51_317_000, 4414) + // Minimum execution time: 113_856_000 picoseconds. + Weight::from_parts(166_357_000, 4414) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -224,8 +228,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1286` // Estimated: `4751` - // Minimum execution time: 36_339_000 picoseconds. - Weight::from_parts(36_919_000, 4751) + // Minimum execution time: 101_287_000 picoseconds. + Weight::from_parts(116_239_000, 4751) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -241,8 +245,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `765` // Estimated: `4230` - // Minimum execution time: 22_412_000 picoseconds. - Weight::from_parts(23_384_000, 4230) + // Minimum execution time: 45_075_000 picoseconds. + Weight::from_parts(70_218_000, 4230) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -252,6 +256,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Farms` (r:1 w:0) /// Proof: `TfgridModule::Farms` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveNodeContracts` (r:1 w:0) /// Proof: `SmartContractModule::ActiveNodeContracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -272,9 +278,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `776` // Estimated: `4241` - // Minimum execution time: 33_453_000 picoseconds. - Weight::from_parts(34_145_000, 4241) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Minimum execution time: 69_351_000 picoseconds. + Weight::from_parts(109_988_000, 4241) + .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) @@ -297,6 +303,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `TfgridModule::NodePower` (r:1 w:0) /// Proof: `TfgridModule::NodePower` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::DedicatedNodesExtraFee` (r:1 w:0) /// Proof: `SmartContractModule::DedicatedNodesExtraFee` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -309,9 +317,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1607` // Estimated: `7547` - // Minimum execution time: 70_012_000 picoseconds. - Weight::from_parts(71_505_000, 7547) - .saturating_add(T::DbWeight::get().reads(14_u64)) + // Minimum execution time: 138_767_000 picoseconds. + Weight::from_parts(147_354_000, 7547) + .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `SmartContractModule::SolutionProviderID` (r:1 w:1) @@ -322,8 +330,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 9_618_000 picoseconds. - Weight::from_parts(10_009_000, 1522) + // Minimum execution time: 19_151_000 picoseconds. + Weight::from_parts(19_702_000, 1522) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -333,8 +341,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `215` // Estimated: `3680` - // Minimum execution time: 12_484_000 picoseconds. - Weight::from_parts(12_854_000, 3680) + // Minimum execution time: 24_809_000 picoseconds. + Weight::from_parts(25_573_000, 3680) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -356,6 +364,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TfgridModule::TwinBoundedAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractBillingInformationByID` (r:1 w:1) /// Proof: `SmartContractModule::ContractBillingInformationByID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::NodeContractResources` (r:1 w:0) @@ -374,9 +384,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2077` // Estimated: `8017` - // Minimum execution time: 83_768_000 picoseconds. - Weight::from_parts(85_121_000, 8017) - .saturating_add(T::DbWeight::get().reads(17_u64)) + // Minimum execution time: 198_668_000 picoseconds. + Weight::from_parts(308_991_000, 8017) + .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:2 w:0) @@ -389,8 +399,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `6335` - // Minimum execution time: 17_804_000 picoseconds. - Weight::from_parts(18_284_000, 6335) + // Minimum execution time: 51_524_000 picoseconds. + Weight::from_parts(58_527_000, 6335) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -402,8 +412,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 15_980_000 picoseconds. - Weight::from_parts(16_271_000, 3954) + // Minimum execution time: 31_567_000 picoseconds. + Weight::from_parts(52_961_000, 3954) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -415,8 +425,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 15_880_000 picoseconds. - Weight::from_parts(16_190_000, 3954) + // Minimum execution time: 33_377_000 picoseconds. + Weight::from_parts(48_525_000, 3954) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -428,8 +438,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_311_000 picoseconds. - Weight::from_parts(16_672_000, 3967) + // Minimum execution time: 45_324_000 picoseconds. + Weight::from_parts(56_352_000, 3967) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -441,8 +451,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_271_000 picoseconds. - Weight::from_parts(17_142_000, 3967) + // Minimum execution time: 47_713_000 picoseconds. + Weight::from_parts(50_466_000, 3967) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -454,8 +464,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 15_620_000 picoseconds. - Weight::from_parts(15_930_000, 3967) + // Minimum execution time: 44_626_000 picoseconds. + Weight::from_parts(51_600_000, 3967) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -473,8 +483,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841` // Estimated: `6781` - // Minimum execution time: 28_193_000 picoseconds. - Weight::from_parts(28_955_000, 6781) + // Minimum execution time: 63_936_000 picoseconds. + Weight::from_parts(91_117_000, 6781) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -484,8 +494,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 7_585_000 picoseconds. - Weight::from_parts(7_805_000, 1522) + // Minimum execution time: 16_676_000 picoseconds. + Weight::from_parts(25_396_000, 1522) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -499,8 +509,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `965` // Estimated: `4430` - // Minimum execution time: 21_100_000 picoseconds. - Weight::from_parts(21_641_000, 4430) + // Minimum execution time: 43_672_000 picoseconds. + Weight::from_parts(62_786_000, 4430) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -520,8 +530,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `733` // Estimated: `4198` - // Minimum execution time: 22_243_000 picoseconds. - Weight::from_parts(23_034_000, 4198) + // Minimum execution time: 45_803_000 picoseconds. + Weight::from_parts(69_341_000, 4198) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -543,6 +553,8 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TfgridModule::TwinBoundedAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveRentContractForNode` (r:1 w:0) /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -559,9 +571,9 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `7590` - // Minimum execution time: 71_696_000 picoseconds. - Weight::from_parts(73_088_000, 7590) - .saturating_add(T::DbWeight::get().reads(13_u64)) + // Minimum execution time: 148_314_000 picoseconds. + Weight::from_parts(230_693_000, 7590) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } } @@ -574,6 +586,8 @@ impl WeightInfo for () { /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::NodePower` (r:1 w:0) /// Proof: `TfgridModule::NodePower` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Farms` (r:1 w:1) /// Proof: `TfgridModule::Farms` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::DedicatedNodesExtraFee` (r:1 w:0) @@ -602,9 +616,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `868` // Estimated: `4333` - // Minimum execution time: 47_449_000 picoseconds. - Weight::from_parts(48_522_000, 4333) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Minimum execution time: 125_637_000 picoseconds. + Weight::from_parts(158_842_000, 4333) + .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) @@ -617,8 +631,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `869` // Estimated: `4334` - // Minimum execution time: 22_553_000 picoseconds. - Weight::from_parts(23_053_000, 4334) + // Minimum execution time: 45_372_000 picoseconds. + Weight::from_parts(73_961_000, 4334) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -640,6 +654,8 @@ impl WeightInfo for () { /// Proof: `TfgridModule::TwinBoundedAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveRentContractForNode` (r:1 w:0) /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -656,9 +672,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `7590` - // Minimum execution time: 73_609_000 picoseconds. - Weight::from_parts(74_771_000, 7590) - .saturating_add(RocksDbWeight::get().reads(13_u64)) + // Minimum execution time: 156_863_000 picoseconds. + Weight::from_parts(256_304_000, 7590) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -681,8 +697,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3805` - // Minimum execution time: 24_006_000 picoseconds. - Weight::from_parts(24_456_000, 3805) + // Minimum execution time: 71_124_000 picoseconds. + Weight::from_parts(77_955_000, 3805) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -708,8 +724,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `949` // Estimated: `4414` - // Minimum execution time: 50_195_000 picoseconds. - Weight::from_parts(51_317_000, 4414) + // Minimum execution time: 113_856_000 picoseconds. + Weight::from_parts(166_357_000, 4414) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -731,8 +747,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1286` // Estimated: `4751` - // Minimum execution time: 36_339_000 picoseconds. - Weight::from_parts(36_919_000, 4751) + // Minimum execution time: 101_287_000 picoseconds. + Weight::from_parts(116_239_000, 4751) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -748,8 +764,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `765` // Estimated: `4230` - // Minimum execution time: 22_412_000 picoseconds. - Weight::from_parts(23_384_000, 4230) + // Minimum execution time: 45_075_000 picoseconds. + Weight::from_parts(70_218_000, 4230) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -759,6 +775,8 @@ impl WeightInfo for () { /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Farms` (r:1 w:0) /// Proof: `TfgridModule::Farms` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveNodeContracts` (r:1 w:0) /// Proof: `SmartContractModule::ActiveNodeContracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -779,9 +797,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `776` // Estimated: `4241` - // Minimum execution time: 33_453_000 picoseconds. - Weight::from_parts(34_145_000, 4241) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Minimum execution time: 69_351_000 picoseconds. + Weight::from_parts(109_988_000, 4241) + .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) @@ -804,6 +822,8 @@ impl WeightInfo for () { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `TfgridModule::NodePower` (r:1 w:0) /// Proof: `TfgridModule::NodePower` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::DedicatedNodesExtraFee` (r:1 w:0) /// Proof: `SmartContractModule::DedicatedNodesExtraFee` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -816,9 +836,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1607` // Estimated: `7547` - // Minimum execution time: 70_012_000 picoseconds. - Weight::from_parts(71_505_000, 7547) - .saturating_add(RocksDbWeight::get().reads(14_u64)) + // Minimum execution time: 138_767_000 picoseconds. + Weight::from_parts(147_354_000, 7547) + .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `SmartContractModule::SolutionProviderID` (r:1 w:1) @@ -829,8 +849,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 9_618_000 picoseconds. - Weight::from_parts(10_009_000, 1522) + // Minimum execution time: 19_151_000 picoseconds. + Weight::from_parts(19_702_000, 1522) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -840,8 +860,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `215` // Estimated: `3680` - // Minimum execution time: 12_484_000 picoseconds. - Weight::from_parts(12_854_000, 3680) + // Minimum execution time: 24_809_000 picoseconds. + Weight::from_parts(25_573_000, 3680) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -863,6 +883,8 @@ impl WeightInfo for () { /// Proof: `TfgridModule::TwinBoundedAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractBillingInformationByID` (r:1 w:1) /// Proof: `SmartContractModule::ContractBillingInformationByID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::NodeContractResources` (r:1 w:0) @@ -881,9 +903,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2077` // Estimated: `8017` - // Minimum execution time: 83_768_000 picoseconds. - Weight::from_parts(85_121_000, 8017) - .saturating_add(RocksDbWeight::get().reads(17_u64)) + // Minimum execution time: 198_668_000 picoseconds. + Weight::from_parts(308_991_000, 8017) + .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:2 w:0) @@ -896,8 +918,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `6335` - // Minimum execution time: 17_804_000 picoseconds. - Weight::from_parts(18_284_000, 6335) + // Minimum execution time: 51_524_000 picoseconds. + Weight::from_parts(58_527_000, 6335) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -909,8 +931,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 15_980_000 picoseconds. - Weight::from_parts(16_271_000, 3954) + // Minimum execution time: 31_567_000 picoseconds. + Weight::from_parts(52_961_000, 3954) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -922,8 +944,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 15_880_000 picoseconds. - Weight::from_parts(16_190_000, 3954) + // Minimum execution time: 33_377_000 picoseconds. + Weight::from_parts(48_525_000, 3954) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -935,8 +957,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_311_000 picoseconds. - Weight::from_parts(16_672_000, 3967) + // Minimum execution time: 45_324_000 picoseconds. + Weight::from_parts(56_352_000, 3967) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -948,8 +970,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_271_000 picoseconds. - Weight::from_parts(17_142_000, 3967) + // Minimum execution time: 47_713_000 picoseconds. + Weight::from_parts(50_466_000, 3967) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -961,8 +983,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 15_620_000 picoseconds. - Weight::from_parts(15_930_000, 3967) + // Minimum execution time: 44_626_000 picoseconds. + Weight::from_parts(51_600_000, 3967) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -980,8 +1002,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841` // Estimated: `6781` - // Minimum execution time: 28_193_000 picoseconds. - Weight::from_parts(28_955_000, 6781) + // Minimum execution time: 63_936_000 picoseconds. + Weight::from_parts(91_117_000, 6781) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -991,8 +1013,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 7_585_000 picoseconds. - Weight::from_parts(7_805_000, 1522) + // Minimum execution time: 16_676_000 picoseconds. + Weight::from_parts(25_396_000, 1522) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1006,8 +1028,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `965` // Estimated: `4430` - // Minimum execution time: 21_100_000 picoseconds. - Weight::from_parts(21_641_000, 4430) + // Minimum execution time: 43_672_000 picoseconds. + Weight::from_parts(62_786_000, 4430) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1027,8 +1049,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `733` // Estimated: `4198` - // Minimum execution time: 22_243_000 picoseconds. - Weight::from_parts(23_034_000, 4198) + // Minimum execution time: 45_803_000 picoseconds. + Weight::from_parts(69_341_000, 4198) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1050,6 +1072,8 @@ impl WeightInfo for () { /// Proof: `TfgridModule::TwinBoundedAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Timestamp::Now` (r:1 w:0) /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:0) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveRentContractForNode` (r:1 w:0) /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -1066,9 +1090,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1650` // Estimated: `7590` - // Minimum execution time: 71_696_000 picoseconds. - Weight::from_parts(73_088_000, 7590) - .saturating_add(RocksDbWeight::get().reads(13_u64)) + // Minimum execution time: 148_314_000 picoseconds. + Weight::from_parts(230_693_000, 7590) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } } diff --git a/substrate-node/pallets/pallet-tfgrid/src/weights.rs b/substrate-node/pallets/pallet-tfgrid/src/weights.rs index 782a8aa3b..342baef22 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/weights.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_tfgrid //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -82,8 +82,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_284_000 picoseconds. - Weight::from_parts(2_405_000, 0) + // Minimum execution time: 7_760_000 picoseconds. + Weight::from_parts(9_173_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -100,8 +100,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3961` - // Minimum execution time: 18_746_000 picoseconds. - Weight::from_parts(19_337_000, 3961) + // Minimum execution time: 37_380_000 picoseconds. + Weight::from_parts(50_833_000, 3961) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -115,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `507` // Estimated: `3972` - // Minimum execution time: 20_800_000 picoseconds. - Weight::from_parts(21_331_000, 3972) + // Minimum execution time: 60_031_000 picoseconds. + Weight::from_parts(65_299_000, 3972) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -130,8 +130,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3918` - // Minimum execution time: 14_998_000 picoseconds. - Weight::from_parts(15_429_000, 3918) + // Minimum execution time: 31_146_000 picoseconds. + Weight::from_parts(47_051_000, 3918) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -141,8 +141,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 12_654_000 picoseconds. - Weight::from_parts(13_035_000, 3877) + // Minimum execution time: 36_321_000 picoseconds. + Weight::from_parts(40_473_000, 3877) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -154,8 +154,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 17_192_000 picoseconds. - Weight::from_parts(17_713_000, 4034) + // Minimum execution time: 38_151_000 picoseconds. + Weight::from_parts(52_836_000, 4034) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -167,8 +167,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 16_260_000 picoseconds. - Weight::from_parts(16_882_000, 4034) + // Minimum execution time: 32_423_000 picoseconds. + Weight::from_parts(46_829_000, 4034) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -196,8 +196,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `905` // Estimated: `11795` - // Minimum execution time: 46_238_000 picoseconds. - Weight::from_parts(47_430_000, 11795) + // Minimum execution time: 90_029_000 picoseconds. + Weight::from_parts(130_789_000, 11795) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -213,8 +213,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `661` // Estimated: `4126` - // Minimum execution time: 26_069_000 picoseconds. - Weight::from_parts(26_841_000, 4126) + // Minimum execution time: 51_884_000 picoseconds. + Weight::from_parts(85_305_000, 4126) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -228,8 +228,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `956` // Estimated: `11846` - // Minimum execution time: 32_842_000 picoseconds. - Weight::from_parts(33_854_000, 11846) + // Minimum execution time: 78_839_000 picoseconds. + Weight::from_parts(99_655_000, 11846) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -245,8 +245,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 17_933_000 picoseconds. - Weight::from_parts(18_254_000, 3919) + // Minimum execution time: 33_838_000 picoseconds. + Weight::from_parts(50_283_000, 3919) .saturating_add(T::DbWeight::get().reads(4_u64)) } /// Storage: `TfgridModule::Farms` (r:1 w:0) @@ -259,8 +259,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779` // Estimated: `4244` - // Minimum execution time: 23_605_000 picoseconds. - Weight::from_parts(24_676_000, 4244) + // Minimum execution time: 60_613_000 picoseconds. + Weight::from_parts(62_014_000, 4244) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -276,14 +276,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dao::FarmWeight` (r:1 w:1) /// Proof: `Dao::FarmWeight` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:0 w:1) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) fn delete_node() -> Weight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `4147` - // Minimum execution time: 26_640_000 picoseconds. - Weight::from_parts(27_292_000, 4147) + // Minimum execution time: 58_291_000 picoseconds. + Weight::from_parts(78_853_000, 4147) .saturating_add(T::DbWeight::get().reads(6_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `TfgridModule::UsersTermsAndConditions` (r:1 w:0) /// Proof: `TfgridModule::UsersTermsAndConditions` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -297,8 +299,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `235` // Estimated: `3700` - // Minimum execution time: 14_107_000 picoseconds. - Weight::from_parts(14_448_000, 3700) + // Minimum execution time: 27_602_000 picoseconds. + Weight::from_parts(42_395_000, 3700) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -310,8 +312,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `428` // Estimated: `3893` - // Minimum execution time: 14_458_000 picoseconds. - Weight::from_parts(14_858_000, 3893) + // Minimum execution time: 41_364_000 picoseconds. + Weight::from_parts(43_444_000, 3893) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -325,8 +327,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `3599` - // Minimum execution time: 12_073_000 picoseconds. - Weight::from_parts(12_394_000, 3599) + // Minimum execution time: 35_299_000 picoseconds. + Weight::from_parts(39_112_000, 3599) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -340,8 +342,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `3847` - // Minimum execution time: 16_020_000 picoseconds. - Weight::from_parts(16_551_000, 3847) + // Minimum execution time: 44_802_000 picoseconds. + Weight::from_parts(49_756_000, 3847) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -353,8 +355,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 9_868_000 picoseconds. - Weight::from_parts(10_139_000, 1619) + // Minimum execution time: 30_200_000 picoseconds. + Weight::from_parts(33_059_000, 1619) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -366,8 +368,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3605` - // Minimum execution time: 7_134_000 picoseconds. - Weight::from_parts(7_604_000, 3605) + // Minimum execution time: 13_830_000 picoseconds. + Weight::from_parts(22_516_000, 3605) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -387,8 +389,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `527` // Estimated: `6467` - // Minimum execution time: 22_352_000 picoseconds. - Weight::from_parts(22_903_000, 6467) + // Minimum execution time: 64_775_000 picoseconds. + Weight::from_parts(69_397_000, 6467) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -404,8 +406,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `605` // Estimated: `4070` - // Minimum execution time: 25_308_000 picoseconds. - Weight::from_parts(25_959_000, 4070) + // Minimum execution time: 50_576_000 picoseconds. + Weight::from_parts(55_237_000, 4070) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -417,26 +419,11 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 12_684_000 picoseconds. - Weight::from_parts(13_095_000, 3868) + // Minimum execution time: 24_901_000 picoseconds. + Weight::from_parts(26_998_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } - fn opt_out_of_v3_billing() -> Weight { - Weight::from_parts(20_000_000, 0) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn add_twin_admin() -> Weight { - Weight::from_parts(10_000_000, 0) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn remove_twin_admin() -> Weight { - Weight::from_parts(10_000_000, 0) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Nodes` (r:1 w:1) @@ -457,8 +444,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `828` // Estimated: `4293` - // Minimum execution time: 31_390_000 picoseconds. - Weight::from_parts(31_870_000, 4293) + // Minimum execution time: 60_135_000 picoseconds. + Weight::from_parts(62_199_000, 4293) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -468,8 +455,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_085_000 picoseconds. - Weight::from_parts(13_495_000, 3877) + // Minimum execution time: 37_384_000 picoseconds. + Weight::from_parts(41_357_000, 3877) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -479,8 +466,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_355_000 picoseconds. - Weight::from_parts(13_636_000, 3877) + // Minimum execution time: 25_288_000 picoseconds. + Weight::from_parts(38_313_000, 3877) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -490,8 +477,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_430_000 picoseconds. - Weight::from_parts(5_671_000, 0) + // Minimum execution time: 18_095_000 picoseconds. + Weight::from_parts(22_993_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::AllowedNodeCertifiers` (r:1 w:1) @@ -500,8 +487,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `355` // Estimated: `1840` - // Minimum execution time: 9_378_000 picoseconds. - Weight::from_parts(9_708_000, 1840) + // Minimum execution time: 18_474_000 picoseconds. + Weight::from_parts(30_915_000, 1840) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -511,8 +498,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `413` // Estimated: `1898` - // Minimum execution time: 11_522_000 picoseconds. - Weight::from_parts(11_943_000, 1898) + // Minimum execution time: 31_528_000 picoseconds. + Weight::from_parts(41_091_000, 1898) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -522,8 +509,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `294` // Estimated: `3759` - // Minimum execution time: 12_774_000 picoseconds. - Weight::from_parts(13_095_000, 3759) + // Minimum execution time: 37_342_000 picoseconds. + Weight::from_parts(40_293_000, 3759) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -537,8 +524,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `572` // Estimated: `4037` - // Minimum execution time: 21_541_000 picoseconds. - Weight::from_parts(22_332_000, 4037) + // Minimum execution time: 43_415_000 picoseconds. + Weight::from_parts(63_666_000, 4037) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -548,8 +535,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 7_715_000 picoseconds. - Weight::from_parts(8_015_000, 1619) + // Minimum execution time: 15_467_000 picoseconds. + Weight::from_parts(17_654_000, 1619) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -565,8 +552,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `621` // Estimated: `4086` - // Minimum execution time: 21_741_000 picoseconds. - Weight::from_parts(22_542_000, 4086) + // Minimum execution time: 62_484_000 picoseconds. + Weight::from_parts(70_463_000, 4086) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -586,8 +573,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792` // Estimated: `4257` - // Minimum execution time: 25_217_000 picoseconds. - Weight::from_parts(26_030_000, 4257) + // Minimum execution time: 71_117_000 picoseconds. + Weight::from_parts(79_965_000, 4257) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -599,8 +586,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3852` - // Minimum execution time: 11_622_000 picoseconds. - Weight::from_parts(12_113_000, 3852) + // Minimum execution time: 23_082_000 picoseconds. + Weight::from_parts(36_426_000, 3852) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -616,10 +603,51 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 17_093_000 picoseconds. - Weight::from_parts(17_382_000, 3919) + // Minimum execution time: 36_465_000 picoseconds. + Weight::from_parts(49_740_000, 3919) .saturating_add(T::DbWeight::get().reads(4_u64)) } + /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) + /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::Nodes` (r:1 w:0) + /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::Farms` (r:1 w:0) + /// Proof: `TfgridModule::Farms` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:1) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn opt_out_of_v3_billing() -> Weight { + // Proof Size summary in bytes: + // Measured: `669` + // Estimated: `4134` + // Minimum execution time: 41_441_000 picoseconds. + Weight::from_parts(66_855_000, 4134) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `TfgridModule::AllowedTwinAdmins` (r:1 w:1) + /// Proof: `TfgridModule::AllowedTwinAdmins` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn add_twin_admin() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `1619` + // Minimum execution time: 24_015_000 picoseconds. + Weight::from_parts(27_477_000, 1619) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `TfgridModule::AllowedTwinAdmins` (r:1 w:1) + /// Proof: `TfgridModule::AllowedTwinAdmins` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn remove_twin_admin() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `1674` + // Minimum execution time: 18_618_000 picoseconds. + Weight::from_parts(28_136_000, 1674) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -630,8 +658,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_284_000 picoseconds. - Weight::from_parts(2_405_000, 0) + // Minimum execution time: 7_760_000 picoseconds. + Weight::from_parts(9_173_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -648,8 +676,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3961` - // Minimum execution time: 18_746_000 picoseconds. - Weight::from_parts(19_337_000, 3961) + // Minimum execution time: 37_380_000 picoseconds. + Weight::from_parts(50_833_000, 3961) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -663,8 +691,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `507` // Estimated: `3972` - // Minimum execution time: 20_800_000 picoseconds. - Weight::from_parts(21_331_000, 3972) + // Minimum execution time: 60_031_000 picoseconds. + Weight::from_parts(65_299_000, 3972) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -678,8 +706,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3918` - // Minimum execution time: 14_998_000 picoseconds. - Weight::from_parts(15_429_000, 3918) + // Minimum execution time: 31_146_000 picoseconds. + Weight::from_parts(47_051_000, 3918) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -689,8 +717,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 12_654_000 picoseconds. - Weight::from_parts(13_035_000, 3877) + // Minimum execution time: 36_321_000 picoseconds. + Weight::from_parts(40_473_000, 3877) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -702,8 +730,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 17_192_000 picoseconds. - Weight::from_parts(17_713_000, 4034) + // Minimum execution time: 38_151_000 picoseconds. + Weight::from_parts(52_836_000, 4034) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -715,8 +743,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 16_260_000 picoseconds. - Weight::from_parts(16_882_000, 4034) + // Minimum execution time: 32_423_000 picoseconds. + Weight::from_parts(46_829_000, 4034) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -744,8 +772,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `905` // Estimated: `11795` - // Minimum execution time: 46_238_000 picoseconds. - Weight::from_parts(47_430_000, 11795) + // Minimum execution time: 90_029_000 picoseconds. + Weight::from_parts(130_789_000, 11795) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -761,8 +789,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `661` // Estimated: `4126` - // Minimum execution time: 26_069_000 picoseconds. - Weight::from_parts(26_841_000, 4126) + // Minimum execution time: 51_884_000 picoseconds. + Weight::from_parts(85_305_000, 4126) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -776,8 +804,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `956` // Estimated: `11846` - // Minimum execution time: 32_842_000 picoseconds. - Weight::from_parts(33_854_000, 11846) + // Minimum execution time: 78_839_000 picoseconds. + Weight::from_parts(99_655_000, 11846) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -793,8 +821,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 17_933_000 picoseconds. - Weight::from_parts(18_254_000, 3919) + // Minimum execution time: 33_838_000 picoseconds. + Weight::from_parts(50_283_000, 3919) .saturating_add(RocksDbWeight::get().reads(4_u64)) } /// Storage: `TfgridModule::Farms` (r:1 w:0) @@ -807,8 +835,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779` // Estimated: `4244` - // Minimum execution time: 23_605_000 picoseconds. - Weight::from_parts(24_676_000, 4244) + // Minimum execution time: 60_613_000 picoseconds. + Weight::from_parts(62_014_000, 4244) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -824,14 +852,16 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Dao::FarmWeight` (r:1 w:1) /// Proof: `Dao::FarmWeight` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:0 w:1) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) fn delete_node() -> Weight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `4147` - // Minimum execution time: 26_640_000 picoseconds. - Weight::from_parts(27_292_000, 4147) + // Minimum execution time: 58_291_000 picoseconds. + Weight::from_parts(78_853_000, 4147) .saturating_add(RocksDbWeight::get().reads(6_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `TfgridModule::UsersTermsAndConditions` (r:1 w:0) /// Proof: `TfgridModule::UsersTermsAndConditions` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -845,8 +875,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `235` // Estimated: `3700` - // Minimum execution time: 14_107_000 picoseconds. - Weight::from_parts(14_448_000, 3700) + // Minimum execution time: 27_602_000 picoseconds. + Weight::from_parts(42_395_000, 3700) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -858,8 +888,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `428` // Estimated: `3893` - // Minimum execution time: 14_458_000 picoseconds. - Weight::from_parts(14_858_000, 3893) + // Minimum execution time: 41_364_000 picoseconds. + Weight::from_parts(43_444_000, 3893) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -873,8 +903,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `3599` - // Minimum execution time: 12_073_000 picoseconds. - Weight::from_parts(12_394_000, 3599) + // Minimum execution time: 35_299_000 picoseconds. + Weight::from_parts(39_112_000, 3599) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -888,8 +918,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `3847` - // Minimum execution time: 16_020_000 picoseconds. - Weight::from_parts(16_551_000, 3847) + // Minimum execution time: 44_802_000 picoseconds. + Weight::from_parts(49_756_000, 3847) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -901,8 +931,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 9_868_000 picoseconds. - Weight::from_parts(10_139_000, 1619) + // Minimum execution time: 30_200_000 picoseconds. + Weight::from_parts(33_059_000, 1619) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -914,8 +944,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3605` - // Minimum execution time: 7_134_000 picoseconds. - Weight::from_parts(7_604_000, 3605) + // Minimum execution time: 13_830_000 picoseconds. + Weight::from_parts(22_516_000, 3605) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -935,8 +965,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `527` // Estimated: `6467` - // Minimum execution time: 22_352_000 picoseconds. - Weight::from_parts(22_903_000, 6467) + // Minimum execution time: 64_775_000 picoseconds. + Weight::from_parts(69_397_000, 6467) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -952,8 +982,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `605` // Estimated: `4070` - // Minimum execution time: 25_308_000 picoseconds. - Weight::from_parts(25_959_000, 4070) + // Minimum execution time: 50_576_000 picoseconds. + Weight::from_parts(55_237_000, 4070) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -965,26 +995,11 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 12_684_000 picoseconds. - Weight::from_parts(13_095_000, 3868) + // Minimum execution time: 24_901_000 picoseconds. + Weight::from_parts(26_998_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } - fn opt_out_of_v3_billing() -> Weight { - Weight::from_parts(20_000_000, 0) - .saturating_add(RocksDbWeight::get().reads(4_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - fn add_twin_admin() -> Weight { - Weight::from_parts(10_000_000, 0) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - fn remove_twin_admin() -> Weight { - Weight::from_parts(10_000_000, 0) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Nodes` (r:1 w:1) @@ -1005,8 +1020,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `828` // Estimated: `4293` - // Minimum execution time: 31_390_000 picoseconds. - Weight::from_parts(31_870_000, 4293) + // Minimum execution time: 60_135_000 picoseconds. + Weight::from_parts(62_199_000, 4293) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1016,8 +1031,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_085_000 picoseconds. - Weight::from_parts(13_495_000, 3877) + // Minimum execution time: 37_384_000 picoseconds. + Weight::from_parts(41_357_000, 3877) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1027,8 +1042,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_355_000 picoseconds. - Weight::from_parts(13_636_000, 3877) + // Minimum execution time: 25_288_000 picoseconds. + Weight::from_parts(38_313_000, 3877) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1038,8 +1053,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_430_000 picoseconds. - Weight::from_parts(5_671_000, 0) + // Minimum execution time: 18_095_000 picoseconds. + Weight::from_parts(22_993_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::AllowedNodeCertifiers` (r:1 w:1) @@ -1048,8 +1063,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `355` // Estimated: `1840` - // Minimum execution time: 9_378_000 picoseconds. - Weight::from_parts(9_708_000, 1840) + // Minimum execution time: 18_474_000 picoseconds. + Weight::from_parts(30_915_000, 1840) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1059,8 +1074,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `413` // Estimated: `1898` - // Minimum execution time: 11_522_000 picoseconds. - Weight::from_parts(11_943_000, 1898) + // Minimum execution time: 31_528_000 picoseconds. + Weight::from_parts(41_091_000, 1898) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1070,8 +1085,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `294` // Estimated: `3759` - // Minimum execution time: 12_774_000 picoseconds. - Weight::from_parts(13_095_000, 3759) + // Minimum execution time: 37_342_000 picoseconds. + Weight::from_parts(40_293_000, 3759) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1085,8 +1100,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `572` // Estimated: `4037` - // Minimum execution time: 21_541_000 picoseconds. - Weight::from_parts(22_332_000, 4037) + // Minimum execution time: 43_415_000 picoseconds. + Weight::from_parts(63_666_000, 4037) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1096,8 +1111,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 7_715_000 picoseconds. - Weight::from_parts(8_015_000, 1619) + // Minimum execution time: 15_467_000 picoseconds. + Weight::from_parts(17_654_000, 1619) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1113,8 +1128,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `621` // Estimated: `4086` - // Minimum execution time: 21_741_000 picoseconds. - Weight::from_parts(22_542_000, 4086) + // Minimum execution time: 62_484_000 picoseconds. + Weight::from_parts(70_463_000, 4086) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1134,8 +1149,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792` // Estimated: `4257` - // Minimum execution time: 25_217_000 picoseconds. - Weight::from_parts(26_030_000, 4257) + // Minimum execution time: 71_117_000 picoseconds. + Weight::from_parts(79_965_000, 4257) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1147,8 +1162,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3852` - // Minimum execution time: 11_622_000 picoseconds. - Weight::from_parts(12_113_000, 3852) + // Minimum execution time: 23_082_000 picoseconds. + Weight::from_parts(36_426_000, 3852) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1164,8 +1179,49 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 17_093_000 picoseconds. - Weight::from_parts(17_382_000, 3919) + // Minimum execution time: 36_465_000 picoseconds. + Weight::from_parts(49_740_000, 3919) .saturating_add(RocksDbWeight::get().reads(4_u64)) } + /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) + /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::Nodes` (r:1 w:0) + /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::Farms` (r:1 w:0) + /// Proof: `TfgridModule::Farms` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::NodeV3BillingOptOut` (r:1 w:1) + /// Proof: `TfgridModule::NodeV3BillingOptOut` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Timestamp::Now` (r:1 w:0) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn opt_out_of_v3_billing() -> Weight { + // Proof Size summary in bytes: + // Measured: `669` + // Estimated: `4134` + // Minimum execution time: 41_441_000 picoseconds. + Weight::from_parts(66_855_000, 4134) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `TfgridModule::AllowedTwinAdmins` (r:1 w:1) + /// Proof: `TfgridModule::AllowedTwinAdmins` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn add_twin_admin() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `1619` + // Minimum execution time: 24_015_000 picoseconds. + Weight::from_parts(27_477_000, 1619) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `TfgridModule::AllowedTwinAdmins` (r:1 w:1) + /// Proof: `TfgridModule::AllowedTwinAdmins` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn remove_twin_admin() -> Weight { + // Proof Size summary in bytes: + // Measured: `189` + // Estimated: `1674` + // Minimum execution time: 18_618_000 picoseconds. + Weight::from_parts(28_136_000, 1674) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/substrate-node/pallets/pallet-tft-bridge/src/weights.rs b/substrate-node/pallets/pallet-tft-bridge/src/weights.rs index 8225b3306..7888a45d1 100644 --- a/substrate-node/pallets/pallet-tft-bridge/src/weights.rs +++ b/substrate-node/pallets/pallet-tft-bridge/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_tft_bridge //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -55,8 +55,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `256` // Estimated: `1741` - // Minimum execution time: 6_913_000 picoseconds. - Weight::from_parts(7_134_000, 1741) + // Minimum execution time: 12_995_000 picoseconds. + Weight::from_parts(13_449_000, 1741) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -66,8 +66,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `289` // Estimated: `1774` - // Minimum execution time: 6_813_000 picoseconds. - Weight::from_parts(7_003_000, 1774) + // Minimum execution time: 12_691_000 picoseconds. + Weight::from_parts(13_252_000, 1774) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -77,8 +77,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_254_000 picoseconds. - Weight::from_parts(2_385_000, 0) + // Minimum execution time: 7_516_000 picoseconds. + Weight::from_parts(8_563_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TFTBridgeModule::WithdrawFee` (r:0 w:1) @@ -87,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_184_000 picoseconds. - Weight::from_parts(2_275_000, 0) + // Minimum execution time: 4_364_000 picoseconds. + Weight::from_parts(4_978_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TFTBridgeModule::DepositFee` (r:0 w:1) @@ -97,8 +97,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_164_000 picoseconds. - Weight::from_parts(2_244_000, 0) + // Minimum execution time: 4_378_000 picoseconds. + Weight::from_parts(4_693_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TFTBridgeModule::WithdrawFee` (r:1 w:0) @@ -115,8 +115,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `253` // Estimated: `3593` - // Minimum execution time: 42_621_000 picoseconds. - Weight::from_parts(43_412_000, 3593) + // Minimum execution time: 82_305_000 picoseconds. + Weight::from_parts(137_671_000, 3593) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -136,8 +136,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3964` - // Minimum execution time: 61_707_000 picoseconds. - Weight::from_parts(62_769_000, 3964) + // Minimum execution time: 113_489_000 picoseconds. + Weight::from_parts(198_034_000, 3964) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -151,8 +151,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `631` // Estimated: `4096` - // Minimum execution time: 24_806_000 picoseconds. - Weight::from_parts(25_419_000, 4096) + // Minimum execution time: 48_359_000 picoseconds. + Weight::from_parts(76_577_000, 4096) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -166,8 +166,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `571` // Estimated: `4036` - // Minimum execution time: 17_683_000 picoseconds. - Weight::from_parts(17_964_000, 4036) + // Minimum execution time: 34_698_000 picoseconds. + Weight::from_parts(50_986_000, 4036) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -179,8 +179,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3850` - // Minimum execution time: 20_929_000 picoseconds. - Weight::from_parts(21_421_000, 3850) + // Minimum execution time: 43_040_000 picoseconds. + Weight::from_parts(67_738_000, 3850) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -194,8 +194,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `560` // Estimated: `4025` - // Minimum execution time: 17_773_000 picoseconds. - Weight::from_parts(18_355_000, 4025) + // Minimum execution time: 34_994_000 picoseconds. + Weight::from_parts(55_424_000, 4025) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -209,8 +209,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `256` // Estimated: `1741` - // Minimum execution time: 6_913_000 picoseconds. - Weight::from_parts(7_134_000, 1741) + // Minimum execution time: 12_995_000 picoseconds. + Weight::from_parts(13_449_000, 1741) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -220,8 +220,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `289` // Estimated: `1774` - // Minimum execution time: 6_813_000 picoseconds. - Weight::from_parts(7_003_000, 1774) + // Minimum execution time: 12_691_000 picoseconds. + Weight::from_parts(13_252_000, 1774) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -231,8 +231,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_254_000 picoseconds. - Weight::from_parts(2_385_000, 0) + // Minimum execution time: 7_516_000 picoseconds. + Weight::from_parts(8_563_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TFTBridgeModule::WithdrawFee` (r:0 w:1) @@ -241,8 +241,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_184_000 picoseconds. - Weight::from_parts(2_275_000, 0) + // Minimum execution time: 4_364_000 picoseconds. + Weight::from_parts(4_978_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TFTBridgeModule::DepositFee` (r:0 w:1) @@ -251,8 +251,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_164_000 picoseconds. - Weight::from_parts(2_244_000, 0) + // Minimum execution time: 4_378_000 picoseconds. + Weight::from_parts(4_693_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TFTBridgeModule::WithdrawFee` (r:1 w:0) @@ -269,8 +269,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `253` // Estimated: `3593` - // Minimum execution time: 42_621_000 picoseconds. - Weight::from_parts(43_412_000, 3593) + // Minimum execution time: 82_305_000 picoseconds. + Weight::from_parts(137_671_000, 3593) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -290,8 +290,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `499` // Estimated: `3964` - // Minimum execution time: 61_707_000 picoseconds. - Weight::from_parts(62_769_000, 3964) + // Minimum execution time: 113_489_000 picoseconds. + Weight::from_parts(198_034_000, 3964) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -305,8 +305,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `631` // Estimated: `4096` - // Minimum execution time: 24_806_000 picoseconds. - Weight::from_parts(25_419_000, 4096) + // Minimum execution time: 48_359_000 picoseconds. + Weight::from_parts(76_577_000, 4096) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -320,8 +320,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `571` // Estimated: `4036` - // Minimum execution time: 17_683_000 picoseconds. - Weight::from_parts(17_964_000, 4036) + // Minimum execution time: 34_698_000 picoseconds. + Weight::from_parts(50_986_000, 4036) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -333,8 +333,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `385` // Estimated: `3850` - // Minimum execution time: 20_929_000 picoseconds. - Weight::from_parts(21_421_000, 3850) + // Minimum execution time: 43_040_000 picoseconds. + Weight::from_parts(67_738_000, 3850) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -348,8 +348,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `560` // Estimated: `4025` - // Minimum execution time: 17_773_000 picoseconds. - Weight::from_parts(18_355_000, 4025) + // Minimum execution time: 34_994_000 picoseconds. + Weight::from_parts(55_424_000, 4025) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } diff --git a/substrate-node/pallets/pallet-tft-price/src/weights.rs b/substrate-node/pallets/pallet-tft-price/src/weights.rs index a62725ab6..811946a7c 100644 --- a/substrate-node/pallets/pallet-tft-price/src/weights.rs +++ b/substrate-node/pallets/pallet-tft-price/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_tft_price //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -61,8 +61,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `235` // Estimated: `6175` - // Minimum execution time: 29_376_000 picoseconds. - Weight::from_parts(30_267_000, 6175) + // Minimum execution time: 83_061_000 picoseconds. + Weight::from_parts(117_132_000, 6175) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -74,8 +74,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `93` // Estimated: `1578` - // Minimum execution time: 4_960_000 picoseconds. - Weight::from_parts(5_109_000, 1578) + // Minimum execution time: 12_908_000 picoseconds. + Weight::from_parts(15_567_000, 1578) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -87,8 +87,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `93` // Estimated: `1578` - // Minimum execution time: 4_929_000 picoseconds. - Weight::from_parts(5_090_000, 1578) + // Minimum execution time: 14_158_000 picoseconds. + Weight::from_parts(15_182_000, 1578) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -116,8 +116,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `235` // Estimated: `6175` - // Minimum execution time: 29_376_000 picoseconds. - Weight::from_parts(30_267_000, 6175) + // Minimum execution time: 83_061_000 picoseconds. + Weight::from_parts(117_132_000, 6175) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -129,8 +129,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `93` // Estimated: `1578` - // Minimum execution time: 4_960_000 picoseconds. - Weight::from_parts(5_109_000, 1578) + // Minimum execution time: 12_908_000 picoseconds. + Weight::from_parts(15_567_000, 1578) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -142,8 +142,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `93` // Estimated: `1578` - // Minimum execution time: 4_929_000 picoseconds. - Weight::from_parts(5_090_000, 1578) + // Minimum execution time: 14_158_000 picoseconds. + Weight::from_parts(15_182_000, 1578) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate-node/pallets/pallet-validator/src/weights.rs b/substrate-node/pallets/pallet-validator/src/weights.rs index 8e0bacce9..acf9c16af 100644 --- a/substrate-node/pallets/pallet-validator/src/weights.rs +++ b/substrate-node/pallets/pallet-validator/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for pallet_validator //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -50,8 +50,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 9_378_000 picoseconds. - Weight::from_parts(9_668_000, 3507) + // Minimum execution time: 31_144_000 picoseconds. + Weight::from_parts(32_794_000, 3507) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -65,8 +65,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `365` // Estimated: `3830` - // Minimum execution time: 23_925_000 picoseconds. - Weight::from_parts(24_466_000, 3830) + // Minimum execution time: 50_987_000 picoseconds. + Weight::from_parts(78_213_000, 3830) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -80,8 +80,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `431` // Estimated: `3896` - // Minimum execution time: 32_140_000 picoseconds. - Weight::from_parts(33_153_000, 3896) + // Minimum execution time: 64_184_000 picoseconds. + Weight::from_parts(104_970_000, 3896) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -91,8 +91,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 8_345_000 picoseconds. - Weight::from_parts(8_717_000, 3507) + // Minimum execution time: 17_493_000 picoseconds. + Weight::from_parts(27_153_000, 3507) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -110,8 +110,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `494` // Estimated: `4687` - // Minimum execution time: 24_096_000 picoseconds. - Weight::from_parts(24_967_000, 4687) + // Minimum execution time: 74_761_000 picoseconds. + Weight::from_parts(79_702_000, 4687) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -131,8 +131,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `558` // Estimated: `4687` - // Minimum execution time: 21_440_000 picoseconds. - Weight::from_parts(21_822_000, 4687) + // Minimum execution time: 65_334_000 picoseconds. + Weight::from_parts(69_925_000, 4687) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -146,8 +146,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 9_378_000 picoseconds. - Weight::from_parts(9_668_000, 3507) + // Minimum execution time: 31_144_000 picoseconds. + Weight::from_parts(32_794_000, 3507) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -161,8 +161,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `365` // Estimated: `3830` - // Minimum execution time: 23_925_000 picoseconds. - Weight::from_parts(24_466_000, 3830) + // Minimum execution time: 50_987_000 picoseconds. + Weight::from_parts(78_213_000, 3830) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -176,8 +176,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `431` // Estimated: `3896` - // Minimum execution time: 32_140_000 picoseconds. - Weight::from_parts(33_153_000, 3896) + // Minimum execution time: 64_184_000 picoseconds. + Weight::from_parts(104_970_000, 3896) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -187,8 +187,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 8_345_000 picoseconds. - Weight::from_parts(8_717_000, 3507) + // Minimum execution time: 17_493_000 picoseconds. + Weight::from_parts(27_153_000, 3507) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -206,8 +206,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `494` // Estimated: `4687` - // Minimum execution time: 24_096_000 picoseconds. - Weight::from_parts(24_967_000, 4687) + // Minimum execution time: 74_761_000 picoseconds. + Weight::from_parts(79_702_000, 4687) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -227,8 +227,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `558` // Estimated: `4687` - // Minimum execution time: 21_440_000 picoseconds. - Weight::from_parts(21_822_000, 4687) + // Minimum execution time: 65_334_000 picoseconds. + Weight::from_parts(69_925_000, 4687) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } diff --git a/substrate-node/pallets/substrate-validator-set/src/weights.rs b/substrate-node/pallets/substrate-validator-set/src/weights.rs index f65ce65a1..3607020a1 100644 --- a/substrate-node/pallets/substrate-validator-set/src/weights.rs +++ b/substrate-node/pallets/substrate-validator-set/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for substrate_validator_set //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2025-09-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2026-02-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `ebea9d7a9918`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `19750001b071`, CPU: `DO-Regular` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -49,8 +49,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `139` // Estimated: `1624` - // Minimum execution time: 13_355_000 picoseconds. - Weight::from_parts(13_676_000, 1624) + // Minimum execution time: 39_555_000 picoseconds. + Weight::from_parts(45_269_000, 1624) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -62,8 +62,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `205` // Estimated: `1690` - // Minimum execution time: 10_951_000 picoseconds. - Weight::from_parts(11_181_000, 1690) + // Minimum execution time: 29_890_000 picoseconds. + Weight::from_parts(36_141_000, 1690) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -75,8 +75,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `172` // Estimated: `1657` - // Minimum execution time: 12_073_000 picoseconds. - Weight::from_parts(12_424_000, 1657) + // Minimum execution time: 32_245_000 picoseconds. + Weight::from_parts(37_468_000, 1657) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -92,8 +92,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `139` // Estimated: `1624` - // Minimum execution time: 13_355_000 picoseconds. - Weight::from_parts(13_676_000, 1624) + // Minimum execution time: 39_555_000 picoseconds. + Weight::from_parts(45_269_000, 1624) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -105,8 +105,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `205` // Estimated: `1690` - // Minimum execution time: 10_951_000 picoseconds. - Weight::from_parts(11_181_000, 1690) + // Minimum execution time: 29_890_000 picoseconds. + Weight::from_parts(36_141_000, 1690) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -118,8 +118,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `172` // Estimated: `1657` - // Minimum execution time: 12_073_000 picoseconds. - Weight::from_parts(12_424_000, 1657) + // Minimum execution time: 32_245_000 picoseconds. + Weight::from_parts(37_468_000, 1657) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } From ead43b010636538359be006e170a8a2d60d0ad6e Mon Sep 17 00:00:00 2001 From: Sameh Abouelsaad Date: Thu, 19 Feb 2026 13:49:39 +0200 Subject: [PATCH 7/7] feat: Add bounded twin admin list with capacity limit and enhanced benchmarking --- clients/tfchain-client-go/utils.go | 1 + clients/tfchain-client-js/lib/node.js | 43 ++++++++++++++++++- docs/architecture/0025-v3-billing-opt-out.md | 9 ++-- .../pallets/pallet-smart-contract/src/mock.rs | 2 + .../pallets/pallet-tfgrid/src/benchmarking.rs | 22 +++++++++- .../pallets/pallet-tfgrid/src/lib.rs | 8 +++- .../pallets/pallet-tfgrid/src/mock.rs | 2 + .../pallets/pallet-tfgrid/src/tests.rs | 21 +++++++++ .../pallet-tfgrid/src/v3_billing_opt_out.rs | 28 ++++++------ substrate-node/runtime/src/lib.rs | 2 + 10 files changed, 117 insertions(+), 21 deletions(-) diff --git a/clients/tfchain-client-go/utils.go b/clients/tfchain-client-go/utils.go index d5e7c0163..5b405eaf8 100644 --- a/clients/tfchain-client-go/utils.go +++ b/clients/tfchain-client-go/utils.go @@ -256,6 +256,7 @@ var tfgridModuleErrors = []string{ "NodeV3BillingOptOutAlreadyEnabled", "AlreadyTwinAdmin", "NotTwinAdmin", + "TwinAdminListFull", } // https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-tft-bridge/src/lib.rs#L152 diff --git a/clients/tfchain-client-js/lib/node.js b/clients/tfchain-client-js/lib/node.js index fd25eccd7..f0c9fcb07 100644 --- a/clients/tfchain-client-js/lib/node.js +++ b/clients/tfchain-client-js/lib/node.js @@ -126,6 +126,42 @@ async function deleteNode (self, id, callback) { .signAndSend(self.key, { nonce }, callback) } +// optOutOfV3Billing opts a node out of v3 billing (farmer only, one-way) +async function optOutOfV3Billing (self, nodeID, callback) { + const nonce = await self.api.rpc.system.accountNextIndex(self.address) + return self.api.tx.tfgridModule + .optOutOfV3Billing(nodeID) + .signAndSend(self.key, { nonce }, callback) +} + +// addTwinAdmin adds an account to the list of twin admins (council origin) +async function addTwinAdmin (self, account, callback) { + const nonce = await self.api.rpc.system.accountNextIndex(self.address) + return self.api.tx.tfgridModule + .addTwinAdmin(account) + .signAndSend(self.key, { nonce }, callback) +} + +// removeTwinAdmin removes an account from the list of twin admins (council origin) +async function removeTwinAdmin (self, account, callback) { + const nonce = await self.api.rpc.system.accountNextIndex(self.address) + return self.api.tx.tfgridModule + .removeTwinAdmin(account) + .signAndSend(self.key, { nonce }, callback) +} + +// getAllowedTwinAdmins returns the list of accounts allowed to deploy on opted-out nodes +async function getAllowedTwinAdmins (self) { + const result = await self.api.query.tfgridModule.allowedTwinAdmins() + return result.toJSON() || [] +} + +// isNodeOptedOutOfV3Billing returns true if the node has opted out of v3 billing +async function isNodeOptedOutOfV3Billing (self, nodeID) { + const result = await self.api.query.tfgridModule.nodeV3BillingOptOut(nodeID) + return !result.isNone +} + async function validateNode (self, farmID) { const farm = await getFarm(self, farmID) if (farm.id !== farmID) { @@ -139,5 +175,10 @@ module.exports = { getNode, getNodeIDByPubkey, deleteNode, - listNodes + listNodes, + optOutOfV3Billing, + addTwinAdmin, + removeTwinAdmin, + getAllowedTwinAdmins, + isNodeOptedOutOfV3Billing } diff --git a/docs/architecture/0025-v3-billing-opt-out.md b/docs/architecture/0025-v3-billing-opt-out.md index 3fa3dd3cd..154d7c65a 100644 --- a/docs/architecture/0025-v3-billing-opt-out.md +++ b/docs/architecture/0025-v3-billing-opt-out.md @@ -15,12 +15,12 @@ During the migration from v3 to Mycelium, farmers need a way to signal that thei ### New Storage Items (pallet-tfgrid) - **`NodeV3BillingOptOut`**: A `StorageMap` tracking which nodes have opted out. Presence in this map is the sole indicator of opt-out status. No storage migration is required as this is an additive change. -- **`AllowedTwinAdmins`**: A `StorageValue>` listing accounts authorized to deploy on opted-out nodes. +- **`AllowedTwinAdmins`**: A `StorageValue>` listing accounts authorized to deploy on opted-out nodes. Bounded to `MaxTwinAdmins` (default: 100) to prevent unbounded storage growth. ### New Extrinsics (pallet-tfgrid) | Extrinsic | Origin | Call Index | -|---|---|---| +| --- | --- | --- | | `opt_out_of_v3_billing(node_id)` | Farmer (signed) | 43 | | `add_twin_admin(account)` | Council (`RestrictedOrigin`) | 44 | | `remove_twin_admin(account)` | Council (`RestrictedOrigin`) | 45 | @@ -49,15 +49,16 @@ This is distinct from `should_waive_standby_rent` (standby power state, rent con ### New Errors -**pallet-smart-contract** +### pallet-smart-contract - `OnlyTwinAdminCanDeployOnThisNode` — returned when a non-admin attempts to deploy on an opted-out node. -**pallet-tfgrid** +### pallet-tfgrid - `NodeV3BillingOptOutAlreadyEnabled` — returned when `opt_out_of_v3_billing` is called on a node that has already opted out. - `AlreadyTwinAdmin` — returned when `add_twin_admin` is called for an account already in the admin list. - `NotTwinAdmin` — returned when `remove_twin_admin` is called for an account not in the admin list, or when the list is empty. +- `TwinAdminListFull` — returned when `add_twin_admin` is called but the list has reached `MaxTwinAdmins` capacity. ## Consequences diff --git a/substrate-node/pallets/pallet-smart-contract/src/mock.rs b/substrate-node/pallets/pallet-smart-contract/src/mock.rs index 3863acfd8..712a555b4 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/mock.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/mock.rs @@ -207,6 +207,7 @@ parameter_types! { pub const MaxInterfaceIpsLength: u32 = 5; pub const MaxInterfacesLength: u32 = 10; pub const MaxFarmPublicIps: u32 = 512; + pub const MaxTwinAdmins: u32 = 10; pub const TimestampHintDrift: u64 = 60; } @@ -234,6 +235,7 @@ impl pallet_tfgrid::Config for TestRuntime { type FarmName = TestFarmName; type MaxFarmNameLength = MaxFarmNameLength; type MaxFarmPublicIps = MaxFarmPublicIps; + type MaxTwinAdmins = MaxTwinAdmins; type MaxInterfacesLength = MaxInterfacesLength; type InterfaceName = TestInterfaceName; type InterfaceMac = TestInterfaceMac; diff --git a/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs b/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs index 86d246814..28362fe40 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs @@ -3,7 +3,7 @@ use super::*; use crate::Pallet as TfgridModule; use frame_benchmarking::{account, benchmarks, whitelisted_caller}; -use frame_support::{assert_ok, BoundedVec}; +use frame_support::{assert_ok, traits::Get, BoundedVec}; use frame_system::{pallet_prelude::BlockNumberFor, EventRecord, Pallet as System, RawOrigin}; // use hex; // use scale_info::prelude::format; @@ -859,7 +859,17 @@ benchmarks! { } // add_twin_admin() + // Worst case: list is at MaxTwinAdmins - 1 before the final insert. + // n ranges from 0 to MaxTwinAdmins - 1; the extrinsic itself adds the (n+1)-th entry. add_twin_admin { + let n in 0 .. (T::MaxTwinAdmins::get() - 1); + for i in 0..n { + let existing: T::AccountId = account("existing", i, 0); + assert_ok!(TfgridModule::::add_twin_admin( + RawOrigin::Root.into(), + existing, + )); + } let caller: T::AccountId = account("Alice", 0, 0); }: _(RawOrigin::Root, caller.clone()) verify { @@ -869,12 +879,22 @@ benchmarks! { } // remove_twin_admin() + // Worst case: list is at MaxTwinAdmins before the remove. + // n ranges from 1 to MaxTwinAdmins; the extrinsic removes one entry from an n-element list. remove_twin_admin { + let n in 1 .. T::MaxTwinAdmins::get(); let caller: T::AccountId = account("Alice", 0, 0); assert_ok!(TfgridModule::::add_twin_admin( RawOrigin::Root.into(), caller.clone(), )); + for i in 1..n { + let existing: T::AccountId = account("existing", i, 0); + assert_ok!(TfgridModule::::add_twin_admin( + RawOrigin::Root.into(), + existing, + )); + } }: _(RawOrigin::Root, caller.clone()) verify { let admins = TfgridModule::::allowed_twin_admins().unwrap_or_default(); diff --git a/substrate-node/pallets/pallet-tfgrid/src/lib.rs b/substrate-node/pallets/pallet-tfgrid/src/lib.rs index 8de26c97e..212bd3dc1 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/lib.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/lib.rs @@ -262,9 +262,11 @@ pub mod pallet { // Global list of accounts authorized to deploy on opted-out nodes. // None = list not initialized (treat as empty = no one allowed). + // Bounded to prevent unbounded storage growth. #[pallet::storage] #[pallet::getter(fn allowed_twin_admins)] - pub type AllowedTwinAdmins = StorageValue<_, Vec, OptionQuery>; + pub type AllowedTwinAdmins = + StorageValue<_, BoundedVec, OptionQuery>; // This storage map maps a node ID to a power state, they node can modify this state // to indicate that it has shut down or came back alive @@ -418,6 +420,9 @@ pub mod pallet { #[pallet::constant] type MaxFarmPublicIps: Get; + #[pallet::constant] + type MaxTwinAdmins: Get; + #[pallet::constant] type MaxInterfacesLength: Get; @@ -652,6 +657,7 @@ pub mod pallet { NodeV3BillingOptOutAlreadyEnabled, AlreadyTwinAdmin, NotTwinAdmin, + TwinAdminListFull, } #[pallet::genesis_config] diff --git a/substrate-node/pallets/pallet-tfgrid/src/mock.rs b/substrate-node/pallets/pallet-tfgrid/src/mock.rs index 0f516d9cc..c44dc1c29 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/mock.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/mock.rs @@ -105,6 +105,7 @@ parameter_types! { pub const MaxInterfaceIpsLength: u32 = 5; pub const MaxInterfacesLength: u32 = 10; pub const MaxFarmPublicIps: u32 = 512; + pub const MaxTwinAdmins: u32 = 10; pub const TimestampHintDrift: u64 = 60; } @@ -133,6 +134,7 @@ impl Config for TestRuntime { type FarmName = TestFarmName; type MaxFarmNameLength = MaxFarmNameLength; type MaxFarmPublicIps = MaxFarmPublicIps; + type MaxTwinAdmins = MaxTwinAdmins; type InterfaceName = TestInterfaceName; type InterfaceMac = TestInterfaceMac; type InterfaceIP = TestInterfaceIp; diff --git a/substrate-node/pallets/pallet-tfgrid/src/tests.rs b/substrate-node/pallets/pallet-tfgrid/src/tests.rs index 85a3f1226..60d7c98cf 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/tests.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/tests.rs @@ -3010,6 +3010,27 @@ fn test_remove_twin_admin_not_exists_fails() { }); } +#[test] +fn test_add_twin_admin_list_full() { + ExternalityBuilder::build().execute_with(|| { + // Fill the list up to MaxTwinAdmins (= 10 in test config) + for i in 0..10u64 { + let account = AccountId::from([i as u8; 32]); + assert_ok!(TfgridModule::add_twin_admin( + RawOrigin::Root.into(), + account, + )); + } + + // The 11th add must fail with TwinAdminListFull + let overflow = AccountId::from([99u8; 32]); + assert_noop!( + TfgridModule::add_twin_admin(RawOrigin::Root.into(), overflow), + Error::::TwinAdminListFull + ); + }); +} + #[test] fn test_delete_opted_out_node_cleans_up_storage() { ExternalityBuilder::build().execute_with(|| { diff --git a/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs b/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs index 687887abb..a1327da07 100644 --- a/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs +++ b/substrate-node/pallets/pallet-tfgrid/src/v3_billing_opt_out.rs @@ -2,7 +2,7 @@ use crate::pallet::{ AllowedTwinAdmins, Error, Event, Farms, NodeV3BillingOptOut, Nodes, TwinIdByAccountID, }; use crate::Config; -use frame_support::{dispatch::DispatchResultWithPostInfo, ensure}; +use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, BoundedVec}; use sp_runtime::SaturatedConversion; use sp_std::vec; @@ -42,19 +42,19 @@ impl crate::Pallet { } pub fn _add_twin_admin(account: T::AccountId) -> DispatchResultWithPostInfo { - match AllowedTwinAdmins::::get() { - Some(mut admins) => { - let location = admins - .binary_search(&account) - .err() - .ok_or(Error::::AlreadyTwinAdmin)?; - admins.insert(location, account.clone()); - AllowedTwinAdmins::::put(admins); - } - None => { - AllowedTwinAdmins::::put(vec![account.clone()]); - } - } + let mut admins = AllowedTwinAdmins::::get() + .unwrap_or_else(|| BoundedVec::new()); + + let location = admins + .binary_search(&account) + .err() + .ok_or(Error::::AlreadyTwinAdmin)?; + + admins + .try_insert(location, account.clone()) + .map_err(|_| Error::::TwinAdminListFull)?; + + AllowedTwinAdmins::::put(admins); Self::deposit_event(Event::TwinAdminAdded(account)); diff --git a/substrate-node/runtime/src/lib.rs b/substrate-node/runtime/src/lib.rs index f353df18a..a9bed3add 100644 --- a/substrate-node/runtime/src/lib.rs +++ b/substrate-node/runtime/src/lib.rs @@ -359,6 +359,7 @@ parameter_types! { pub const MaxInterfaceIpsLength: u32 = 10; pub const MaxInterfacesLength: u32 = 10; pub const MaxFarmPublicIps: u32 = 512; + pub const MaxTwinAdmins: u32 = 100; pub const TimestampHintDrift: u64 = 60; } @@ -372,6 +373,7 @@ impl pallet_tfgrid::Config for Runtime { type TermsAndConditions = pallet_tfgrid::terms_cond::TermsAndConditions; type MaxFarmNameLength = MaxFarmNameLength; type MaxFarmPublicIps = MaxFarmPublicIps; + type MaxTwinAdmins = MaxTwinAdmins; type FarmName = pallet_tfgrid::farm::FarmName; type MaxInterfacesLength = MaxInterfacesLength; type InterfaceName = pallet_tfgrid::interface::InterfaceName;