diff --git a/clients/tfchain-client-go/contract_events.go b/clients/tfchain-client-go/contract_events.go index 556f33c9b..47a8c0ceb 100644 --- a/clients/tfchain-client-go/contract_events.go +++ b/clients/tfchain-client-go/contract_events.go @@ -242,3 +242,33 @@ type NodeExtraFeeSet struct { ExtraFee types.U64 `json:"extra_fee"` Topics []types.Hash } + +type RentWaived struct { + Phase types.Phase + ContractID types.U64 `json:"contract_id"` + Topics []types.Hash +} + +type ContractGracePeriodElapsed struct { + Phase types.Phase + ContractID types.U64 `json:"contract_id"` + GracePeriod types.U64 `json:"grace_period"` + Topics []types.Hash +} + +type ContractPaymentOverdrawn struct { + Phase types.Phase + ContractID types.U64 `json:"contract_id"` + Timestamp types.U64 `json:"timestamp"` + PartiallyBilledAmount types.U128 `json:"partially_billed_amount"` + Overdraft types.U128 `json:"overdraft"` + Topics []types.Hash +} + +type RewardDistributed struct { + Phase types.Phase + ContractID types.U64 `json:"contract_id"` + StandardRewards types.U128 `json:"standard_rewards"` + AdditionalRewards types.U128 `json:"additional_rewards"` + Topics []types.Hash +} diff --git a/clients/tfchain-client-go/events.go b/clients/tfchain-client-go/events.go index 0910e780a..2538fa374 100644 --- a/clients/tfchain-client-go/events.go +++ b/clients/tfchain-client-go/events.go @@ -389,6 +389,10 @@ type EventRecords struct { SmartContractModule_ServiceContractBilled []ServiceContractBilled //nolint:stylecheck,golint SmartContractModule_BillingFrequencyChanged []BillingFrequencyChanged //nolint:stylecheck,golint SmartContractModule_NodeExtraFeeSet []NodeExtraFeeSet //nolint:stylecheck,golint + SmartContractModule_RentWaived []RentWaived //nolint:stylecheck,golint + SmartContractModule_ContractGracePeriodElapsed []ContractGracePeriodElapsed //nolint:stylecheck,golint + SmartContractModule_ContractPaymentOverdrawn []ContractPaymentOverdrawn //nolint:stylecheck,golint + SmartContractModule_RewardDistributed []RewardDistributed //nolint:stylecheck,golint // farm events TfgridModule_FarmStored []FarmStored //nolint:stylecheck,golint diff --git a/clients/tfchain-client-go/utils.go b/clients/tfchain-client-go/utils.go index cd2283d17..e1d214240 100644 --- a/clients/tfchain-client-go/utils.go +++ b/clients/tfchain-client-go/utils.go @@ -127,6 +127,8 @@ var smartContractModuleErrors = []string{ "WrongAuthority", "UnauthorizedToChangeSolutionProviderId", "UnauthorizedToSetExtraFee", + "RewardDistributionError", + "ContractPaymentStateNotExists", } // https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-tfgrid/src/lib.rs#L442 diff --git a/docs/architecture/0023-billing-refactor.md b/docs/architecture/0023-billing-refactor.md new file mode 100644 index 000000000..0ad1d310c --- /dev/null +++ b/docs/architecture/0023-billing-refactor.md @@ -0,0 +1,48 @@ +# 23. Billing Refactor in pallet-smart-contract Module + +Date: 2024-08-18 + +## Status + +Accepted + +## Context + +The billing logic within the pallet-smart-contract module faced several issues, including critical bugs, inefficiencies in handling validators, and inadequate fund reservation mechanisms. +The goal of this refactor was to address these issues while enhancing the overall reliability and robustness of the billing process. + +## Decision + +The following architectural decisions were made to improve the billing logic: + +### Refactoring Billing Logic + +- Enhanced Tracking: +Improved tracking mechanisms were introduced for contract payments, especially during grace periods and when handling overdue payments. +The new ContractPaymentState was introduced to accurately manage contract payment states and resolve liquidity issues. +- Overdraft Handling: +Partial payments are now allowed, where users can cover part of their billing due if they lack sufficient funds for the full amount. Overdraft are tracked separately. +- Fund Reservation: +The use of balance locks/freezes was replaced with a more reliable reservation system, reducing issues related to fund availability for reward distribution. + +### Improved Off-Chain Worker Logic + +- Runtime Verification: +The is_next_block_author function was removed, with verification now occurring at runtime. +This change ensures transaction fees are reliably waived for validators and still prevents duplicate transactions. + +### New Events Introduced + +- ContractGracePeriodElapsed: Indicates that a contract's grace period has elapsed. +- ContractPaymentOverdrawn: Indicates that a contract's payment is overdrawn. +- RewardDistributed: Indicates that rewards have been distributed. + +### Certified vs DIY Capacity + +The system now correctly charges certified capacity at a higher rate (25% more) than DIY capacity. + +## Consequences + +- Increased Robustness: The billing process is now more robust and less prone to errors, particularly in scenarios involving partial payments and fund reservations. +- Better Visibility: The introduction of new events and improved logging provides better visibility into the billing and payment processes, aiding in debugging and monitoring. +- Backward Compatibility: While significant refactoring has been done, efforts were made to ensure backward compatibility where possible, especially concerning contract migration. diff --git a/substrate-node/node/src/benchmarking.rs b/substrate-node/node/src/benchmarking.rs index 06f55b394..24d086117 100644 --- a/substrate-node/node/src/benchmarking.rs +++ b/substrate-node/node/src/benchmarking.rs @@ -11,7 +11,7 @@ use sp_core::{Encode, Pair}; use sp_inherents::{InherentData, InherentDataProvider}; use sp_keyring::Sr25519Keyring; use sp_runtime::{OpaqueExtrinsic, SaturatedConversion}; -use tfchain_runtime as runtime; +use tfchain_runtime::{self as runtime, pallet_smart_contract}; use std::{sync::Arc, time::Duration}; @@ -132,6 +132,7 @@ pub fn create_benchmark_extrinsic( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), + pallet_smart_contract::types::ContractIdProvides::::new(), ); let raw_payload = runtime::SignedPayload::from_raw( @@ -146,6 +147,7 @@ pub fn create_benchmark_extrinsic( (), (), (), + (), ), ); let signature = raw_payload.using_encoded(|e| sender.sign(e)); diff --git a/substrate-node/pallets/pallet-burning/src/weights.rs b/substrate-node/pallets/pallet-burning/src/weights.rs index c840829cf..021e73116 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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_841_000 picoseconds. - Weight::from_parts(27_372_000, 1594) + // Minimum execution time: 26_780_000 picoseconds. + Weight::from_parts(27_291_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_841_000 picoseconds. - Weight::from_parts(27_372_000, 1594) + // Minimum execution time: 26_780_000 picoseconds. + Weight::from_parts(27_291_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 4301ffe5a..3445de116 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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: 19_196_000 picoseconds. - Weight::from_parts(19_487_000, 4687) + // Minimum execution time: 19_277_000 picoseconds. + Weight::from_parts(20_188_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: 26_179_000 picoseconds. - Weight::from_parts(26_751_000, 4444) + // Minimum execution time: 26_390_000 picoseconds. + Weight::from_parts(26_840_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: 18_154_000 picoseconds. - Weight::from_parts(18_755_000, 4687) + // Minimum execution time: 18_616_000 picoseconds. + Weight::from_parts(18_985_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_757_000 picoseconds. - Weight::from_parts(25_268_000, 4687) + // Minimum execution time: 25_117_000 picoseconds. + Weight::from_parts(25_498_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: 19_196_000 picoseconds. - Weight::from_parts(19_487_000, 4687) + // Minimum execution time: 19_277_000 picoseconds. + Weight::from_parts(20_188_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: 26_179_000 picoseconds. - Weight::from_parts(26_751_000, 4444) + // Minimum execution time: 26_390_000 picoseconds. + Weight::from_parts(26_840_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: 18_154_000 picoseconds. - Weight::from_parts(18_755_000, 4687) + // Minimum execution time: 18_616_000 picoseconds. + Weight::from_parts(18_985_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_757_000 picoseconds. - Weight::from_parts(25_268_000, 4687) + // Minimum execution time: 25_117_000 picoseconds. + Weight::from_parts(25_498_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 1e49afb32..05947e5e8 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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: 7_293_000 picoseconds. - Weight::from_parts(7_574_000, 0) + // Minimum execution time: 11_372_000 picoseconds. + Weight::from_parts(12_032_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: 12_784_000 picoseconds. - Weight::from_parts(13_205_000, 3611) + // Minimum execution time: 12_414_000 picoseconds. + Weight::from_parts(12_854_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: 7_293_000 picoseconds. - Weight::from_parts(7_574_000, 0) + // Minimum execution time: 11_372_000 picoseconds. + Weight::from_parts(12_032_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: 12_784_000 picoseconds. - Weight::from_parts(13_205_000, 3611) + // Minimum execution time: 12_414_000 picoseconds. + Weight::from_parts(12_854_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/benchmarking.rs b/substrate-node/pallets/pallet-smart-contract/src/benchmarking.rs index d19457f4a..60b67866c 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/benchmarking.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/benchmarking.rs @@ -305,11 +305,11 @@ benchmarks! { let contract = SmartContractModule::::contracts(contract_id).unwrap(); // Get contract cost before billing to take into account nu - let (cost, discount_level) = contract.calculate_contract_cost_tft(balance_init_amount, elapsed_seconds).unwrap(); + let (cost, discount_level) = contract.calculate_contract_cost_tft(balance_init_amount, elapsed_seconds, None).unwrap(); }: _(RawOrigin::Signed(farmer), contract_id) verify { - let lock = SmartContractModule::::contract_number_of_cylces_billed(contract_id); - assert_eq!(lock.amount_locked, cost); + let contract_payment_state = SmartContractModule::::contract_payment_state(contract_id).unwrap(); + assert_eq!(contract_payment_state.standard_reserve, cost); let contract_bill = types::ContractBill { contract_id, timestamp: SmartContractModule::::get_current_timestamp_in_secs(), diff --git a/substrate-node/pallets/pallet-smart-contract/src/billing.rs b/substrate-node/pallets/pallet-smart-contract/src/billing.rs index 9ae4f8721..1ad253516 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/billing.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/billing.rs @@ -1,27 +1,28 @@ use crate::*; use frame_support::{ - dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, + dispatch::{DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo}, ensure, - traits::{Currency, ExistenceRequirement, LockableCurrency, OnUnbalanced, WithdrawReasons}, + traits::{BalanceStatus, Currency, DefensiveSaturating, ReservableCurrency, StoredMap}, }; + use frame_system::{ - offchain::{SendSignedTransaction, SignMessage, Signer}, + offchain::{SendSignedTransaction, Signer}, pallet_prelude::BlockNumberFor, }; use sp_core::Get; use sp_runtime::{ - traits::{CheckedAdd, CheckedSub, Convert, Zero}, - DispatchResult, Perbill, SaturatedConversion, + traits::{Convert, Saturating, Zero}, + Perbill, SaturatedConversion, }; -use sp_std::vec::Vec; +use sp_std::{cmp::max, vec::Vec}; impl Pallet { + // Let offchain worker check if there are contracts on + // billing loop at current index and try to bill them pub fn bill_contracts_for_block(block_number: BlockNumberFor) { - // Let offchain worker check if there are contracts on - // billing loop at current index and try to bill them let index = Self::get_billing_loop_index_from_block_number(block_number); - let contract_ids = ContractsToBillAt::::get(index); + if contract_ids.is_empty() { log::info!( "No contracts to bill at block {:?}, index: {:?}", @@ -32,173 +33,308 @@ impl Pallet { } log::info!( - "{:?} contracts to bill at block {:?}", + "Contracts to bill at block {:?}: {:?}", + block_number, contract_ids, - block_number ); + let mut succeeded_contracts = Vec::new(); + let mut failed_contracts = Vec::new(); + let mut skipped_contracts = Vec::new(); + let mut missing_contracts = Vec::new(); + let mut already_sent_contracts = Vec::new(); + for contract_id in contract_ids { - if let Some(c) = Contracts::::get(contract_id) { - if let types::ContractData::NodeContract(node_contract) = c.contract_type { - // Is there IP consumption to bill? - let bill_ip = node_contract.public_ips > 0; - - // Is there CU/SU consumption to bill? - // No need for preliminary call to contains_key() because default resource value is empty - let bill_cu_su = !NodeContractResources::::get(contract_id).used.is_empty(); - - // Is there NU consumption to bill? - // No need for preliminary call to contains_key() because default amount_unbilled is 0 - let bill_nu = - ContractBillingInformationByID::::get(contract_id).amount_unbilled > 0; - - // Don't bill if no IP/CU/SU/NU to be billed - if !bill_ip && !bill_cu_su && !bill_nu { - continue; + if let Some(contract) = Contracts::::get(contract_id) { + if Self::should_bill_contract(&contract) { + match Self::submit_signed_transaction_for_contract_billing(contract_id) { + Ok(()) => succeeded_contracts.push(contract_id), + Err(Error::::OffchainSignedTxCannotSign) => { + failed_contracts.push(contract_id); + } + Err(Error::::OffchainSignedTxAlreadySent) => { + already_sent_contracts.push(contract_id); + } + Err(_) => { + failed_contracts.push(contract_id); + } } + } else { + skipped_contracts.push(contract_id); } - let _res = Self::bill_contract_using_signed_transaction(contract_id); + } else { + missing_contracts.push(contract_id); } } - } - pub fn bill_contract_using_signed_transaction(contract_id: u64) -> Result<(), Error> { - let signer = Signer::::AuthorityId>::any_account(); + // Log the results at the end of the function + if !succeeded_contracts.is_empty() { + log::info!( + "Successfully submitted signed transactions for contracts: {:?}", + succeeded_contracts + ); + } - // Only allow the author of the next block to trigger the billing - Self::is_next_block_author(&signer)?; + if !already_sent_contracts.is_empty() { + log::info!( + "Signed transactions for contracts were already sent: {:?}", + already_sent_contracts + ); + } - if !signer.can_sign() { + if !skipped_contracts.is_empty() { + log::info!( + "Skipped billing node contracts (no IP/CU/SU/NU to bill): {:?}", + skipped_contracts + ); + } + + if !failed_contracts.is_empty() { log::error!( - "failed billing contract {:?} account cannot be used to sign transaction", - contract_id, + "Failed to submit signed transactions for contracts: {:?}", + failed_contracts ); + } + + if !missing_contracts.is_empty() { + log::error!("Contracts not found in storage: {:?}", missing_contracts); + } + } + + fn should_bill_contract(contract: &types::Contract) -> bool { + match &contract.contract_type { + types::ContractData::NodeContract(node_contract) => { + let bill_ip = node_contract.public_ips > 0; + let bill_cu_su = !NodeContractResources::::get(contract.contract_id) + .used + .is_empty(); + let bill_nu = ContractBillingInformationByID::::get(contract.contract_id) + .amount_unbilled + > 0; + + return bill_ip || bill_cu_su || bill_nu; + } + _ => true, + } + } + + pub fn submit_signed_transaction_for_contract_billing( + contract_id: u64, + ) -> Result<(), Error> { + let signer = Signer::::AuthorityId>::all_accounts(); + + if !signer.can_sign() { return Err(>::OffchainSignedTxCannotSign); } let result = signer.send_signed_transaction(|_acct| Call::bill_contract_for_block { contract_id }); - if let Some((acc, res)) = result { - // if res is an error this means sending the transaction failed - // this means the transaction was already send before (probably by another node) - // unfortunately the error is always empty (substrate just logs the error and - // returns Err()) - if res.is_err() { - log::error!( - "signed transaction failed for billing contract {:?} using account {:?}", - contract_id, - acc.id - ); - return Err(>::OffchainSignedTxAlreadySent); - } + if result.iter().any(|(_, res)| res.is_ok()) { return Ok(()); } - log::error!("No local account available"); - return Err(>::OffchainSignedTxNoLocalAccountAvailable); + + Err(>::OffchainSignedTxAlreadySent) } // Bills a contract (NodeContract, NameContract or RentContract) // Calculates how much TFT is due by the user and distributes the rewards pub fn bill_contract(contract_id: u64) -> DispatchResultWithPostInfo { - let mut contract = Contracts::::get(contract_id).ok_or(Error::::ContractNotExists)?; - - // Bill rent contract only if node is online - if let types::ContractData::RentContract(rc) = &contract.contract_type { - if let Some(node) = pallet_tfgrid::Nodes::::get(rc.node_id) { - // No need for preliminary call to contains_key() because default node power value is Up - let node_power = pallet_tfgrid::NodePower::::get(node.id); - if node_power.is_standby() { - return Ok(().into()); - } - } - } + let mut contract = Contracts::::get(contract_id).ok_or_else(|| { + log::error!("Contract not exists: {:?}", contract_id); + Error::::ContractNotExists + })?; + let src_twin = pallet_tfgrid::Twins::::get(contract.twin_id).ok_or_else(|| { + log::error!("Twin not exists: {:?}", contract.twin_id); + Error::::TwinNotExists + })?; + let pricing_policy = pallet_tfgrid::PricingPolicies::::get(1).ok_or_else(|| { + log::error!("Pricing policy not exists"); + Error::::PricingPolicyNotExists + })?; + + // In case contract is not a name contract ensure the node, farm and farmer twin exists + let (farmer_twin, node_certification) = + if !matches!(contract.contract_type, types::ContractData::NameContract(_)) { + let node = + pallet_tfgrid::Nodes::::get(contract.get_node_id()).ok_or_else(|| { + log::error!("Node not exists for contract_id: {:?}", contract_id); + Error::::NodeNotExists + })?; + let farm = pallet_tfgrid::Farms::::get(node.farm_id).ok_or_else(|| { + log::error!("Farm not exists for node_id: {:?}", node.farm_id); + Error::::FarmNotExists + })?; + let farmer_twin = + pallet_tfgrid::Twins::::get(farm.twin_id).ok_or_else(|| { + log::error!("Twin not exists for farm_id: {:?}", farm.twin_id); + Error::::TwinNotExists + })?; + (Some(farmer_twin), Some(node.certification)) + } else { + (None, None) + }; + + let mut contract_payment_state = ContractPaymentState::::get(contract.contract_id).ok_or_else(|| { + log::error!("Contract payment state not exists for contract_id {}", contract_id); + Error::::ContractPaymentStateNotExists + })?; - let twin = - pallet_tfgrid::Twins::::get(contract.twin_id).ok_or(Error::::TwinNotExists)?; - let usable_balance = Self::get_usable_balance(&twin.account_id); - let stash_balance = Self::get_stash_balance(twin.id); - let total_balance = usable_balance - .checked_add(&stash_balance) - .unwrap_or(BalanceOf::::zero()); + log::trace!( + "Contract payment state [before billing]: {:?}", + contract_payment_state + ); - let now = Self::get_current_timestamp_in_secs(); + // Calculate user total usable balance + let twin_usable_balance = Self::get_usable_balance(&src_twin.account_id); + let stash_usable_balance = Self::get_stash_balance(src_twin.id); + let total_usable_balance = + twin_usable_balance.defensive_saturating_add(stash_usable_balance); + let now: u64 = Self::get_current_timestamp_in_secs(); - // Calculate amount of seconds elapsed based on the contract lock struct - let mut contract_lock = ContractLock::::get(contract.contract_id); - let seconds_elapsed = now.checked_sub(contract_lock.lock_updated).unwrap_or(0); + // Calculate amount of seconds elapsed based on the contract payment state + let seconds_elapsed = + now.defensive_saturating_sub(contract_payment_state.last_updated_seconds); - // Calculate total amount due - let (regular_amount_due, discount_received) = - contract.calculate_contract_cost_tft(total_balance, seconds_elapsed)?; - let extra_amount_due = match &contract.contract_type { + let should_waive_payment = match &contract.contract_type { types::ContractData::RentContract(rc) => { - contract.calculate_extra_fee_cost_tft(rc.node_id, seconds_elapsed)? + let node_power = pallet_tfgrid::NodePower::::get(rc.node_id); + node_power.is_standby() } - _ => BalanceOf::::zero(), - }; - let amount_due = regular_amount_due - .checked_add(&extra_amount_due) - .unwrap_or(BalanceOf::::zero()); - - // If there is nothing to be paid and the contract is not in state delete, return - // Can be that the users cancels the contract in the same block that it's getting billed - // where elapsed seconds would be 0, but we still have to distribute rewards - if amount_due == BalanceOf::::zero() && !contract.is_state_delete() { - log::debug!("amount to be billed is 0, nothing to do"); - return Ok(().into()); + _ => false, }; - // Calculate total amount locked - let regular_lock_amount = contract_lock - .amount_locked - .checked_add(®ular_amount_due) - .unwrap_or(BalanceOf::::zero()); - let extra_lock_amount = contract_lock - .extra_amount_locked - .checked_add(&extra_amount_due) - .unwrap_or(BalanceOf::::zero()); - let lock_amount = regular_lock_amount - .checked_add(&extra_lock_amount) - .unwrap_or(BalanceOf::::zero()); - - // Handle grace - let contract = Self::handle_grace(&mut contract, usable_balance, lock_amount)?; - - // Only update contract lock in state (Created, GracePeriod) - if !matches!(contract.state, types::ContractState::Deleted(_)) { - // increment cycles billed and update the internal lock struct - contract_lock.lock_updated = now; - contract_lock.cycles += 1; - contract_lock.amount_locked = regular_lock_amount; - contract_lock.extra_amount_locked = extra_lock_amount; + if should_waive_payment { + log::info!("Waiving rent for contract_id: {:?}", contract.contract_id); + Self::deposit_event(Event::RentWaived { + contract_id: contract.contract_id, + }); + // Although no billing required here, in deleted state, we should continue the billing process for contracts to distribute rewards if any and clean up storage + if matches!(contract.state, types::ContractState::Created) { + // So for created rent contracts, if the node is in standby, don't expect the billing cycle to advance + return Ok(().into()); + } } - // If still in grace period, no need to continue doing locking and other stuff - if matches!(contract.state, types::ContractState::GracePeriod(_)) { - log::info!("contract {} is still in grace", contract.contract_id); - ContractLock::::insert(contract.contract_id, &contract_lock); + // Calculate the due amount + let (standard_amount_due, discount_received) = if should_waive_payment { + (BalanceOf::::zero(), types::DiscountLevel::None) + } else { + contract + .calculate_contract_cost_tft( + total_usable_balance, + seconds_elapsed, + node_certification, + ) + .map_err(|e| { + log::error!("Error while calculating contract cost: {:?}", e); + e + })? + }; + + let additional_amount_due = + if let types::ContractData::RentContract(rc) = &contract.contract_type { + if should_waive_payment { + BalanceOf::::zero() + } else { + contract.calculate_extra_fee_cost_tft(rc.node_id, seconds_elapsed) + } + } else { + BalanceOf::::zero() + }; + + let total_amount_due = standard_amount_due.defensive_saturating_add(additional_amount_due); + log::debug!( + "Seconds elapsed since last bill {:?}, standard amount due: {:?}, additional amount due: {:?}, total amount due: {:?}, Discount received: {:?}", + seconds_elapsed, + standard_amount_due, + additional_amount_due, + total_amount_due, + discount_received + ); + + // If the amount due is zero and the contract is not in deleted state, don't bill the contract (mostly node contract on a rented node) + if total_amount_due.is_zero() && !matches!(contract.state, types::ContractState::Deleted(_)) + { + log::info!( + "Amount to be billed is 0 and contract state is {:?}, nothing to do with contract_id: {:?}", + contract.state, + contract.contract_id + ); return Ok(().into()); } - // Handle contract lock operations - Self::handle_lock(contract, &mut contract_lock, amount_due)?; + // Calculate the amount needed to be reserved from the user's balance + // Should be the total amount due for current cycle + any overdraft from previous cycles + let standard_amount_to_reserve = + standard_amount_due.defensive_saturating_add(contract_payment_state.standard_overdraft); + let additional_amount_to_reserve = additional_amount_due + .defensive_saturating_add(contract_payment_state.additional_overdraft); + let total_amount_to_reserve = + standard_amount_to_reserve.defensive_saturating_add(additional_amount_to_reserve); + + let has_sufficient_fund = + ::Currency::can_reserve(&src_twin.account_id, total_amount_to_reserve); + let current_block = >::block_number().saturated_into::(); - // Always emit a contract billed event - let contract_bill = types::ContractBill { - contract_id: contract.contract_id, - timestamp: Self::get_current_timestamp_in_secs(), - discount_level: discount_received.clone(), - amount_billed: amount_due.saturated_into::(), - }; - Self::deposit_event(Event::ContractBilled(contract_bill)); + _ = Self::manage_contract_state(&mut contract, has_sufficient_fund, current_block); + + if has_sufficient_fund { + log::info!("Billing contract_id: {:?}, Contract state: {:?}, This cycle amount due: {:?}, Total (include previous overdraft) {:?}", + contract.contract_id, + contract.state, + total_amount_due, + total_amount_to_reserve + ); + Self::reserve_funds( + &mut contract_payment_state, + standard_amount_due, + additional_amount_due, + &src_twin, + &contract, + now, + total_amount_to_reserve, + discount_received, + )?; + } else { + log::info!( + "Contract payment overdrawn for contract_id: {:?}, Contract state: {:?}, This cycle overdue: {:?}, Twin have: {:?}, Previous overdraft: {:?}", + contract.contract_id, + contract.state, + total_amount_due, + twin_usable_balance, + contract_payment_state.get_overdraft() + ); + Self::overdraft_funds( + &mut contract_payment_state, + standard_amount_due, + additional_amount_due, + &src_twin, + &contract, + now, + twin_usable_balance, + )?; + } - // If the contract is in delete state, remove all associated storage + // Distribute rewards + Self::remit_funds( + &contract, + &mut contract_payment_state, + &src_twin, + &farmer_twin, + &pricing_policy, + )?; + + // Housekeeping for contracts in deleted state if matches!(contract.state, types::ContractState::Deleted(_)) { + log::info!( + "contract id {:?} in deleted state. clean up storage.", + contract.contract_id + ); return Self::remove_contract(contract.contract_id); } - // If contract is node contract, set the amount unbilled back to 0 + // Reset NU amount if the contract is a node contract if matches!(contract.contract_type, types::ContractData::NodeContract(_)) { let mut contract_billing_info = ContractBillingInformationByID::::get(contract.contract_id); @@ -209,418 +345,419 @@ impl Pallet { ); } - // Finally update the lock - ContractLock::::insert(contract.contract_id, &contract_lock); - - log::info!("successfully billed contract with id {:?}", contract_id,); + contract_payment_state.last_updated_seconds = now; + log::trace!( + "Contract payment state [after billing]: {:?}", + contract_payment_state + ); + ContractPaymentState::::insert(contract.contract_id, &contract_payment_state); Ok(().into()) } - fn handle_grace( + // Handles the transition between different contract states based on the fund availability + // May emits one of ContractGracePeriodStarted, ContractGracePeriodEnded, ContractGracePeriodElapsed events + fn manage_contract_state( contract: &mut types::Contract, - usable_balance: BalanceOf, - amount_due: BalanceOf, - ) -> Result<&mut types::Contract, DispatchErrorWithPostInfo> { - let current_block = >::block_number().saturated_into::(); - let node_id = contract.get_node_id(); - + has_sufficient_fund: bool, + current_block: u64, + ) -> DispatchResultWithPostInfo { match contract.state { + types::ContractState::GracePeriod(_) if has_sufficient_fund => { + // Manage transition from GracePeriod to Created + log::info!("Contract {:?} is in grace period, but balance is recharged, moving to created state at block {:?}", contract.contract_id, current_block); + Self::update_contract_state(contract, &types::ContractState::Created)?; + Self::deposit_event(Event::ContractGracePeriodEnded { + contract_id: contract.contract_id, + node_id: contract.get_node_id(), + twin_id: contract.twin_id, + }); + Self::synchronize_associated_node_contract_states( + contract, + types::ContractState::Created, + )?; + } types::ContractState::GracePeriod(grace_start) => { - // if the usable balance is recharged, we can move the contract to created state again - if usable_balance > amount_due { - Self::update_contract_state(contract, &types::ContractState::Created)?; - Self::deposit_event(Event::ContractGracePeriodEnded { + // Manage transition from GracePeriod to Deleted + let diff = current_block.defensive_saturating_sub(grace_start); + log::debug!( + "Contract {:?} in grace period, elapsed blocks: {:?}", + contract.contract_id, + diff + ); + if diff >= T::GracePeriod::get() { + log::info!("Contract {:?} state changed to deleted at block {:?} due to an expired grace period.", contract.contract_id, current_block); + Self::deposit_event(Event::ContractGracePeriodElapsed { contract_id: contract.contract_id, - node_id, - twin_id: contract.twin_id, + grace_period: diff, }); - // If the contract is a rent contract, also move state on associated node contracts - Self::handle_grace_rent_contract(contract, types::ContractState::Created)?; - } else { - let diff = current_block.checked_sub(grace_start).unwrap_or(0); - // If the contract grace period ran out, we can decomission the contract - if diff >= T::GracePeriod::get() { - Self::update_contract_state( - contract, - &types::ContractState::Deleted(types::Cause::OutOfFunds), - )?; - } - } - } - types::ContractState::Created => { - // if the user ran out of funds, move the contract to be in a grace period - // dont lock the tokens because there is nothing to lock - // we can still update the internal contract lock object to figure out later how much was due - // whilst in grace period - if amount_due >= usable_balance { - log::info!( - "Grace period started at block {:?} due to lack of funds", - current_block - ); Self::update_contract_state( contract, - &types::ContractState::GracePeriod(current_block), - )?; - // We can't lock the amount due on the contract's lock because the user ran out of funds - Self::deposit_event(Event::ContractGracePeriodStarted { - contract_id: contract.contract_id, - node_id, - twin_id: contract.twin_id, - block_number: current_block.saturated_into(), - }); - // If the contract is a rent contract, also move associated node contract to grace period - Self::handle_grace_rent_contract( - contract, - types::ContractState::GracePeriod(current_block), + &types::ContractState::Deleted(types::Cause::OutOfFunds), )?; } } + types::ContractState::Created if !has_sufficient_fund => { + // Manage transition from Created to GracePeriod + log::info!( + "Grace period started at block {:?} due to lack of funds", + current_block + ); + Self::update_contract_state( + contract, + &types::ContractState::GracePeriod(current_block.saturated_into()), + )?; + Self::deposit_event(Event::ContractGracePeriodStarted { + contract_id: contract.contract_id, + node_id: contract.get_node_id(), + twin_id: contract.twin_id, + block_number: current_block.saturated_into(), + }); + Self::synchronize_associated_node_contract_states( + contract, + types::ContractState::GracePeriod(current_block), + )?; + } _ => (), } - - Ok(contract) + Ok(().into()) } - fn handle_grace_rent_contract( - contract: &mut types::Contract, - state: types::ContractState, + // Holding funds from a user's account to guarantee that they are available later. + // Emits ContractBilled event + fn reserve_funds( + contract_payment_state: &mut types::ContractPaymentState>, + standard_amount_due: BalanceOf, + additional_amount_due: BalanceOf, + src_twin: &pallet_tfgrid::types::Twin, + contract: &types::Contract, + now: u64, + total_amount_to_reserve: BalanceOf, + discount_received: types::DiscountLevel, ) -> DispatchResultWithPostInfo { - match &contract.contract_type { - types::ContractData::RentContract(rc) => { - let active_node_contracts = ActiveNodeContracts::::get(rc.node_id); - for ctr_id in active_node_contracts { - let mut ctr = - Contracts::::get(ctr_id).ok_or(Error::::ContractNotExists)?; - Self::update_contract_state(&mut ctr, &state)?; - - match state { - types::ContractState::Created => { - Self::deposit_event(Event::ContractGracePeriodEnded { - contract_id: ctr_id, - node_id: rc.node_id, - twin_id: ctr.twin_id, - }); - } - types::ContractState::GracePeriod(block_number) => { - Self::deposit_event(Event::ContractGracePeriodStarted { - contract_id: ctr_id, - node_id: rc.node_id, - twin_id: ctr.twin_id, - block_number, - }); - } - _ => (), - }; - } - } - _ => (), + ::Currency::reserve(&src_twin.account_id, total_amount_to_reserve).map_err( + |e| { + // should never happen as we called can_reserve first to check if the funds are available + log::error!("Error while reserving amount due: {:?}", e); + e + }, + )?; + contract_payment_state.settle_overdraft(); + contract_payment_state.reserve_standard_amount(standard_amount_due); + contract_payment_state.reserve_additional_amount(additional_amount_due); + let contract_bill = types::ContractBill { + contract_id: contract.contract_id, + timestamp: now, + discount_level: discount_received.clone(), + amount_billed: total_amount_to_reserve.saturated_into::(), }; - + log::info!("Contract billed: {:?}", contract_bill); + Self::deposit_event(Event::ContractBilled(contract_bill)); Ok(().into()) } - fn handle_lock( - contract: &mut types::Contract, - contract_lock: &mut types::ContractLock>, - amount_due: BalanceOf, + // Increasing the overdraft in the user's account + // Emits ContractPaymentOverdrawn event + fn overdraft_funds( + contract_payment_state: &mut types::ContractPaymentState>, + standard_amount_due: BalanceOf, + additional_amount_due: BalanceOf, + src_twin: &pallet_tfgrid::types::Twin, + contract: &types::Contract, + now: u64, + reservable: BalanceOf, ) -> DispatchResultWithPostInfo { - let now = Self::get_current_timestamp_in_secs(); - - // Only lock an amount from the user's balance if the contract is in create state - // The lock is specified on the user's account, since a user can have multiple contracts - // Just extend the lock with the amount due for this contract billing period (lock will be created if not exists) - let twin = - pallet_tfgrid::Twins::::get(contract.twin_id).ok_or(Error::::TwinNotExists)?; - if matches!(contract.state, types::ContractState::Created) { - let mut locked_balance = Self::get_locked_balance(&twin.account_id); - locked_balance = locked_balance - .checked_add(&amount_due) - .unwrap_or(BalanceOf::::zero()); - ::Currency::extend_lock( - GRID_LOCK_ID, - &twin.account_id, - locked_balance, - WithdrawReasons::all(), - ); - } - - let canceled_and_not_zero = - contract.is_state_delete() && contract_lock.has_some_amount_locked(); - // When the cultivation rewards are ready to be distributed or it's in delete state - // Unlock all reserved balance and distribute - if contract_lock.cycles >= T::DistributionFrequency::get() || canceled_and_not_zero { - // First remove the lock, calculate how much locked balance needs to be unlocked and re-lock the remaining locked balance - let locked_balance = Self::get_locked_balance(&twin.account_id); - let new_locked_balance = - match locked_balance.checked_sub(&contract_lock.total_amount_locked()) { - Some(b) => b, - None => BalanceOf::::zero(), - }; - ::Currency::remove_lock(GRID_LOCK_ID, &twin.account_id); - - // Fetch twin balance, if the amount locked in the contract lock exceeds the current unlocked - // balance we can only transfer out the remaining balance - // https://github.com/threefoldtech/tfchain/issues/479 - let min_balance = ::Currency::minimum_balance(); - let mut twin_balance = match new_locked_balance { - bal if bal > min_balance => { - ::Currency::set_lock( - GRID_LOCK_ID, - &twin.account_id, - new_locked_balance, - WithdrawReasons::all(), - ); - Self::get_usable_balance(&twin.account_id) - } - _ => Self::get_usable_balance(&twin.account_id) - .checked_sub(&min_balance) - .unwrap_or(BalanceOf::::zero()), - }; + contract_payment_state.overdraft_standard_amount(standard_amount_due); + contract_payment_state.overdraft_additional_amount(additional_amount_due); + // Reserve as much as possible from the user's account to cover part of the amount overdue + let overdue = standard_amount_due.saturating_add(additional_amount_due); + let overdrawn = overdue.saturating_sub(reservable); + ::Currency::reserve(&src_twin.account_id, reservable).map_err(|e| { + log::error!("Error while reserving partial amount due: {:?}", e); + e + })?; + contract_payment_state.settle_partial_overdraft(reservable); + log::info!("Partial amount reserved: {:?}", reservable); + log::info!("Overdrawn: {:?}", overdrawn); + Self::deposit_event(Event::ContractPaymentOverdrawn { + contract_id: contract.contract_id, + timestamp: now, + // This is the partial amount successfully reserved from the user's account in this billing cycle + partially_billed_amount: reservable, + // This is the overdraft caused by insufficient funds for the contract payment in this billing cycle + overdraft: overdrawn, + }); + Ok(().into()) + } - // First, distribute extra cultivation rewards if any - if contract_lock.has_extra_amount_locked() { + // Orchestrate the distribution of rewards + // Emits RewardDistributed event + // No-Op if contract neither in deleted state nor the distribution frequency is reached + fn remit_funds( + contract: &types::Contract, + contract_payment_state: &mut types::ContractPaymentState>, + src_twin: &pallet_tfgrid::types::Twin, + farmer_twin: &Option>, + pricing_policy: &pallet_tfgrid::types::PricingPolicy, + ) -> DispatchResult { + contract_payment_state.cycles.defensive_saturating_inc(); + let is_deleted = matches!(contract.state, types::ContractState::Deleted(_)); + let should_distribute_rewards = + contract_payment_state.cycles >= T::DistributionFrequency::get() || is_deleted; + if should_distribute_rewards && contract_payment_state.has_reserve() { + // At this point we don't expect any distribution failure since every fund to transfer should have been accumulated in account reserve along previous billing cycles + let standard_rewards = contract_payment_state.standard_reserve; + let additional_rewards = contract_payment_state.additional_reserve; + // distribute additional rewards to the farm twin + + if let types::ContractData::RentContract(_) = &contract.contract_type { log::info!( - "twin balance {:?} contract lock extra amount {:?}", - twin_balance, - contract_lock.extra_amount_locked + "Distributing additional rewards from twin {:?} with amount {:?}", + src_twin.id, + additional_rewards, ); - - match Self::distribute_extra_cultivation_rewards( - &contract, - twin_balance.min(contract_lock.extra_amount_locked), - ) { - Ok(_) => {} - Err(err) => { - log::error!( - "error while distributing extra cultivation rewards {:?}", - err - ); - return Err(err); + match Self::distribute_additional_rewards(src_twin, farmer_twin, additional_rewards) + { + Ok(_) => (), + Err(e) => { + log::error!("Error while distributing additional rewards: {:?}", e); + if !is_deleted { + return Err(e); + } } - }; - - // Update twin balance after distribution - twin_balance = Self::get_usable_balance(&twin.account_id); + } + contract_payment_state.reset_additional_reserve(); } log::info!( - "twin balance {:?} contract lock amount {:?}", - twin_balance, - contract_lock.amount_locked + "Distributing standard rewards from twin {:?} with amount {:?}", + src_twin.id, + standard_rewards, ); - - // Fetch the default pricing policy - let pricing_policy = pallet_tfgrid::PricingPolicies::::get(1) - .ok_or(Error::::PricingPolicyNotExists)?; - - // Then, distribute cultivation rewards - match Self::distribute_cultivation_rewards( - &contract, - &pricing_policy, - twin_balance.min(contract_lock.amount_locked), + // Distribute standard rewards + match Self::distribute_standard_rewards( + src_twin, + farmer_twin, + standard_rewards, + pricing_policy, ) { - Ok(_) => {} - Err(err) => { - log::error!("error while distributing cultivation rewards {:?}", err); - return Err(err); + Ok(_) => (), + Err(e) => { + log::error!("Error while distributing standard rewards: {:?}", e); + if !is_deleted { + return Err(e); + } } }; - // Reset contract lock values - contract_lock.lock_updated = now; - contract_lock.amount_locked = BalanceOf::::zero(); - contract_lock.extra_amount_locked = BalanceOf::::zero(); - contract_lock.cycles = 0; - } + contract_payment_state.reset_standard_reserve(); + contract_payment_state.reset_cycles(); + log::info!( + "Rewards distributed for contract_id: {:?}", + contract.contract_id + ); + Self::deposit_event(Event::RewardDistributed { + contract_id: contract.contract_id, + standard_rewards, + additional_rewards, + }); + } else { + log::debug!( + "Not distributing rewards for contract_id: {:?}, cycles: {:?}, reserved amount: {:?}", + contract.contract_id, + contract_payment_state.cycles, + contract_payment_state.get_reserve() + ); + } Ok(().into()) } - fn distribute_extra_cultivation_rewards( - contract: &types::Contract, - amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - log::info!( - "Distributing extra cultivation rewards for contract {:?} with amount {:?}", - contract.contract_id, - amount, - ); - - // If the amount is zero, return - if amount == BalanceOf::::zero() { + fn distribute_additional_rewards( + src_twin: &pallet_tfgrid::types::Twin, + farmer_twin: &Option>, + additional_rewards: BalanceOf, + ) -> DispatchResult { + if additional_rewards.is_zero() { return Ok(().into()); } - // Fetch source twin = dedicated node user - let src_twin = - pallet_tfgrid::Twins::::get(contract.twin_id).ok_or(Error::::TwinNotExists)?; - - // Fetch destination twin = farmer - let dst_twin = match &contract.contract_type { - types::ContractData::RentContract(rc) => { - let node = - pallet_tfgrid::Nodes::::get(rc.node_id).ok_or(Error::::NodeNotExists)?; - let farm = pallet_tfgrid::Farms::::get(node.farm_id) - .ok_or(Error::::FarmNotExists)?; - pallet_tfgrid::Twins::::get(farm.twin_id).ok_or(Error::::TwinNotExists)? - } - _ => { - return Err(DispatchErrorWithPostInfo::from( - Error::::InvalidContractType, - )); - } - }; - - // Send 100% to the node's owner (farmer) - log::debug!( - "Transfering: {:?} from contract twin {:?} to farmer account {:?}", - &amount, - &src_twin.account_id, - &dst_twin.account_id, - ); - ::Currency::transfer( - &src_twin.account_id, - &dst_twin.account_id, - amount, - ExistenceRequirement::KeepAlive, - )?; + if let Some(dst_twin) = farmer_twin { + log::debug!( + "Transferring: {:?} (100%) from twin {:?} to farmer twin {:?}", + additional_rewards, + src_twin.id, + dst_twin.id + ); + Self::transfer_reserved( + &src_twin.account_id, + &dst_twin.account_id, + additional_rewards, + )?; + } Ok(().into()) } - // Following: https://library.threefold.me/info/threefold#/tfgrid/farming/threefold__proof_of_utilization - fn distribute_cultivation_rewards( - contract: &types::Contract, + // Transferring the held or reserved funds from the user's account to the beneficiaries (foundation, staking pool, and farmer) + fn distribute_standard_rewards( + src_twin: &pallet_tfgrid::types::Twin, + farmer_twin: &Option>, + standard_rewards: BalanceOf, pricing_policy: &pallet_tfgrid::types::PricingPolicy, - amount: BalanceOf, - ) -> DispatchResultWithPostInfo { - log::info!( - "Distributing cultivation rewards for contract {:?} with amount {:?}", - contract.contract_id, - amount, - ); - - // If the amount is zero, return - if amount == BalanceOf::::zero() { + ) -> DispatchResult { + if standard_rewards.is_zero() { return Ok(().into()); } - // fetch source twin - let twin = - pallet_tfgrid::Twins::::get(contract.twin_id).ok_or(Error::::TwinNotExists)?; - - // Send 10% to the foundation - let foundation_share = Perbill::from_percent(10) * amount; - log::debug!( - "Transfering: {:?} from contract twin {:?} to foundation account {:?}", - &foundation_share, - &twin.account_id, - &pricing_policy.foundation_account - ); - ::Currency::transfer( - &twin.account_id, - &pricing_policy.foundation_account, - foundation_share, - ExistenceRequirement::KeepAlive, - )?; - - // TODO: send 5% to the staking pool account - let staking_pool_share = Perbill::from_percent(5) * amount; + // Calculate and transfer staking pool share (10%) + let staking_pool_share = Perbill::from_percent(10) * standard_rewards; let staking_pool_account = T::StakingPoolAccount::get(); log::debug!( - "Transfering: {:?} from contract twin {:?} to staking pool account {:?}", - &staking_pool_share, - &twin.account_id, - &staking_pool_account, + "Transferring: {:?} (10%) from twin {:?} to staking pool account {:?}", + staking_pool_share, + src_twin.id, + staking_pool_account, ); - ::Currency::transfer( - &twin.account_id, + Self::transfer_reserved( + &src_twin.account_id, &staking_pool_account, staking_pool_share, - ExistenceRequirement::KeepAlive, )?; - let mut sales_share = 50; - - if let Some(provider_id) = contract.solution_provider_id { - if let Some(solution_provider) = SolutionProviders::::get(provider_id) { - let total_take: u8 = solution_provider - .providers - .iter() - .map(|provider| provider.take) - .sum(); - sales_share -= total_take; - - if !solution_provider - .providers - .iter() - .map(|provider| { - let share = Perbill::from_percent(provider.take as u32) * amount; - log::debug!( - "Transfering: {:?} from contract twin {:?} to provider account {:?}", - &share, - &twin.account_id, - &provider.who - ); - ::Currency::transfer( - &twin.account_id, - &provider.who, - share, - ExistenceRequirement::KeepAlive, - ) - }) - .filter(|result| result.is_err()) - .collect::>() - .is_empty() - { - return Err(DispatchErrorWithPostInfo::from( - Error::::InvalidProviderConfiguration, - )); - } - } - }; - - if sales_share > 0 { - let share = Perbill::from_percent(sales_share.into()) * amount; - // Transfer the remaining share to the sales account - // By default it is 50%, if a contract has solution providers it can be less + let (foundation_percent, foundation_share) = if let Some(dst_twin) = farmer_twin { + // Where 3node utilized (Node and Rent contracts) + // Calculate foundation share (40%) + let foundation_percent = 40; + let foundation_share = Perbill::from_percent(foundation_percent) * standard_rewards; + // Calculate and transfer farmer share (50%) + // We calculate it by subtract all previously send amounts with the initial to avoid accumulating rounding errors. + let total_distributed = foundation_share + staking_pool_share; + let farmer_share = standard_rewards.defensive_saturating_sub(total_distributed); log::debug!( - "Transfering: {:?} from contract twin {:?} to sales account {:?}", - &share, - &twin.account_id, - &pricing_policy.certified_sales_account + "Transferring: {:?} (50%) from twin {:?} to farmer twin {:?}", + farmer_share, + src_twin.id, + dst_twin.id ); - ::Currency::transfer( - &twin.account_id, - &pricing_policy.certified_sales_account, - share, - ExistenceRequirement::KeepAlive, - )?; - } - - // Burn 35%, to not have any imbalance in the system, subtract all previously send amounts with the initial - let amount_to_burn = - (Perbill::from_percent(50) * amount) - foundation_share - staking_pool_share; + Self::transfer_reserved(&src_twin.account_id, &dst_twin.account_id, farmer_share)?; - let to_burn = T::Currency::withdraw( - &twin.account_id, - amount_to_burn, - WithdrawReasons::FEE, - ExistenceRequirement::KeepAlive, - )?; + (foundation_percent, foundation_share) + } else { + // Where no 3node utilized (Name contracts) + // Calculate foundation share (90%) + let foundation_percent = 90; + // We calculate it by subtract all previously send amounts with the initial to avoid accumulating rounding errors. + let foundation_share = standard_rewards.defensive_saturating_sub(staking_pool_share); + (foundation_percent, foundation_share) + }; + // Transfer foundation share log::debug!( - "Burning: {:?} from contract twin {:?}", - amount_to_burn, - &twin.account_id + "Transferring: {:?} ({:}%) from twin {:?} to foundation account {:?}", + foundation_share, + foundation_percent, + src_twin.id, + pricing_policy.foundation_account, ); - T::Burn::on_unbalanced(to_burn); + Self::transfer_reserved( + &src_twin.account_id, + &pricing_policy.foundation_account, + foundation_share, + )?; - Self::deposit_event(Event::TokensBurned { - contract_id: contract.contract_id, - amount: amount_to_burn, - }); + Ok(().into()) + } + + // Transfer reserved funds to a beneficiary + fn transfer_reserved( + src_account: &T::AccountId, + dst_account: &T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(().into()); + } + + let result = if Self::account_exists(&dst_account) { + // Default case: repatriate_reserved is efficient but requires the beneficiary account to exist + ::Currency::repatriate_reserved( + &src_account, + &dst_account, + amount, + BalanceStatus::Free, + ) + } else { + // Defensive measure: less efficient than repatriate_reserved, but works for non-existent accounts + log::info!("Beneficiary account does not exist. The account will be created"); + let (slashed, remainder) = + ::Currency::slash_reserved(&src_account, amount); + if remainder.is_zero() { + // This may fail to create the account if the amount is too low (less than EXISTENTIAL_DEPOSIT) but nothing we can do about it + ::Currency::resolve_creating(dst_account, slashed); + } + Ok(remainder) + }; + + match result { + // No remainder: the full amount was successfully deducted from the reserve and transferred to the beneficiary + Ok(remainder) if remainder.is_zero() => Ok(().into()), + // Partial remainder: A portion of the amount wasn't successfully deducted from the reserve. + // This should only occur if on-chain logic has introduced a liquid restriction on the source account, or if there's a bug + Ok(remainder) => { + log::error!( + "Failed to transfer the whole amount: wanted {:?}, remainder {:?}", + amount, + remainder + ); + Err(Error::::RewardDistributionError.into()) + } + // This should only occur if the destination account is unable to receive the funds + Err(e) => { + log::error!( + "Failed to transfer reserved balance: error: {:?}. source: {:?}, destination: {:?}", + e, src_account, dst_account + ); + Err(e) + } + } + } + + // Managing the states of node contracts associated with a rent contract to transition them to the appropriate state (either Created or GracePeriod). + fn synchronize_associated_node_contract_states( + contract: &mut types::Contract, + state: types::ContractState, + ) -> DispatchResultWithPostInfo { + match &contract.contract_type { + types::ContractData::RentContract(rc) => { + let active_node_contracts = ActiveNodeContracts::::get(rc.node_id); + for ctr_id in active_node_contracts { + let mut ctr = + Contracts::::get(ctr_id).ok_or(Error::::ContractNotExists)?; + Self::update_contract_state(&mut ctr, &state)?; + + match state { + types::ContractState::Created => { + Self::deposit_event(Event::ContractGracePeriodEnded { + contract_id: ctr_id, + node_id: rc.node_id, + twin_id: ctr.twin_id, + }); + } + types::ContractState::GracePeriod(block_number) => { + Self::deposit_event(Event::ContractGracePeriodStarted { + contract_id: ctr_id, + node_id: rc.node_id, + twin_id: ctr.twin_id, + block_number, + }); + } + _ => (), + }; + } + } + _ => (), + }; Ok(().into()) } @@ -638,7 +775,7 @@ impl Pallet { } // Inserts a contract in a billing loop where the index is the contract id % billing frequency - // This way, we don't need to reinsert the contract everytime it gets billed + // This way, we don't need to re-insert the contract every time it gets billed pub fn insert_contract_in_billing_loop(contract_id: u64) { let index = Self::get_billing_loop_index_from_contract_id(contract_id); let mut contract_ids = ContractsToBillAt::::get(index); @@ -690,25 +827,6 @@ impl Pallet { Ok(().into()) } - // Get the usable balance of an account - // This is the balance minus the minimum balance - pub fn get_usable_balance(account_id: &T::AccountId) -> BalanceOf { - let balance = pallet_balances::pallet::Pallet::::usable_balance(account_id); - let b = balance.saturated_into::(); - BalanceOf::::saturated_from(b) - } - - fn get_locked_balance(account_id: &T::AccountId) -> BalanceOf { - let usable_balance = Self::get_usable_balance(account_id); - let free_balance = ::Currency::free_balance(account_id); - - let locked_balance = free_balance.checked_sub(&usable_balance); - match locked_balance { - Some(balance) => balance, - None => BalanceOf::::zero(), - } - } - fn get_stash_balance(twin_id: u32) -> BalanceOf { let account_id = pallet_tfgrid::TwinBoundedAccountID::::get(twin_id); match account_id { @@ -717,44 +835,39 @@ impl Pallet { } } - // Validates if the given signer is the next block author based on the validators in session - // This can be used if an extrinsic should be refunded by the author in the same block - // It also requires that the keytype inserted for the offchain workers is the validator key - fn is_next_block_author( - signer: &Signer::AuthorityId>, - ) -> Result<(), Error> { - let author = >::author(); - let validators = >::validators(); - - // Sign some arbitrary data in order to get the AccountId, maybe there is another way to do this? - let signed_message = signer.sign_message(&[0]); - if let Some(signed_message_data) = signed_message { - if let Some(block_author) = author { - let validator = - ::ValidatorIdOf::convert(block_author.clone()) - .ok_or(Error::::IsNotAnAuthority)?; - - let validator_count = validators.len(); - let author_index = (validators.iter().position(|a| a == &validator).unwrap_or(0) - + 1) - % validator_count; - - let signer_validator_account = - ::ValidatorIdOf::convert( - signed_message_data.0.id.clone(), - ) - .ok_or(Error::::IsNotAnAuthority)?; - - if signer_validator_account != validators[author_index] { - return Err(Error::::WrongAuthority); - } - } - } - - Ok(().into()) + // Retrieve the liquid balance (amount that is neither reserved nor frozen). + // The check can_reserve(get_reservable_balance(acc)) should always return true. + // Returns free - max (ED, Frozen) + pub fn get_usable_balance(account_id: &T::AccountId) -> BalanceOf { + let account = T::AccountStore::get(account_id); + let free = account.free; + let frozen = account.frozen; + let reserved = account.reserved; + let minimum_balance = + <::Currency as Currency>::minimum_balance() + .saturated_into::(); + // Get the reservable balance + let reservable = free.saturating_sub(max( + ::Balance::saturated_from(minimum_balance), + frozen, + )); + log::debug!("Free balance: {:?} Reserved balance: {:?} Locked balance: {:?} Reservable balance: {:?}", free, reserved, frozen, reservable); + let b = reservable.saturated_into::(); + BalanceOf::::saturated_from(b) } pub fn get_current_timestamp_in_secs() -> u64 { >::get().saturated_into::() / 1000 } + + pub fn is_validator(account_id: T::AccountId) -> bool { + let validators = pallet_session::Pallet::::validators(); + + ::ValidatorIdOf::convert(account_id.clone()) + .map_or(false, |validator_id| validators.contains(&validator_id)) + } + + fn account_exists(account_id: &T::AccountId) -> bool { + >::account_exists(&account_id.clone().into()) + } } diff --git a/substrate-node/pallets/pallet-smart-contract/src/cost.rs b/substrate-node/pallets/pallet-smart-contract/src/cost.rs index 64686ac60..69a4b7e39 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/cost.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/cost.rs @@ -9,6 +9,8 @@ use tfchain_support::{ types::NodeCertification, }; +pub const CERTIFIED_INCREASE_FACTOR: f64 = 1.25; + impl types::Contract { pub fn get_billing_info(&self) -> types::ContractBillingInformation { pallet::ContractBillingInformationByID::::get(self.contract_id) @@ -18,10 +20,10 @@ impl types::Contract { &self, balance: BalanceOf, seconds_elapsed: u64, + certification_type: Option, ) -> Result<(BalanceOf, types::DiscountLevel), DispatchErrorWithPostInfo> { // Fetch the default pricing policy and certification type let pricing_policy = pallet_tfgrid::PricingPolicies::::get(1).unwrap(); - let certification_type = NodeCertification::Diy; // Calculate the cost for a contract, can be any of: // - NodeContract @@ -30,12 +32,11 @@ impl types::Contract { let total_cost = self.calculate_contract_cost_units_usd(&pricing_policy, seconds_elapsed)?; - // If cost is 0, reinsert to be billed at next interval if total_cost == 0 { return Ok((BalanceOf::::zero(), types::DiscountLevel::None)); } - let total_cost_tft_64 = calculate_cost_in_tft_from_units_usd::(total_cost)?; + let total_cost_tft_64 = calculate_cost_in_tft_from_units_usd::(total_cost); // Calculate the amount due and discount received based on the total_cost amount due let (amount_due, discount_received) = calculate_discount_tft::( @@ -114,18 +115,14 @@ impl types::Contract { } // Calculates the cost of extra fee for a dedicated node in TFT. - pub fn calculate_extra_fee_cost_tft( - &self, - node_id: u32, - seconds_elapsed: u64, - ) -> Result, DispatchErrorWithPostInfo> { + pub fn calculate_extra_fee_cost_tft(&self, node_id: u32, seconds_elapsed: u64) -> BalanceOf { let cost = calculate_extra_fee_cost_units_usd::(node_id, seconds_elapsed); if cost == 0 { - return Ok(BalanceOf::::zero()); + return BalanceOf::::zero(); } - let cost_tft = calculate_cost_in_tft_from_units_usd::(cost)?; + let cost_tft = calculate_cost_in_tft_from_units_usd::(cost); - Ok(BalanceOf::::saturated_from(cost_tft)) + BalanceOf::::saturated_from(cost_tft) } } @@ -178,7 +175,7 @@ impl types::ServiceContract { } // Calculate the cost in TFT for service contract - let total_cost_tft_64 = calculate_cost_in_tft_from_units_usd::(total_cost)?; + let total_cost_tft_64 = calculate_cost_in_tft_from_units_usd::(total_cost); // convert to balance object let amount_due: BalanceOf = BalanceOf::::saturated_from(total_cost_tft_64); @@ -297,7 +294,7 @@ pub fn calculate_discount_tft( amount_due: u64, seconds_elapsed: u64, balance: BalanceOf, - certification_type: NodeCertification, + certification_type: Option, ) -> (BalanceOf, types::DiscountLevel) { if amount_due == 0 { return (BalanceOf::::zero(), types::DiscountLevel::None); @@ -329,8 +326,9 @@ pub fn calculate_discount_tft( let mut amount_due = U64F64::from_num(amount_due) * discount_received.price_multiplier(); // Certified capacity costs 25% more - if certification_type == NodeCertification::Certified { - amount_due = amount_due * U64F64::from_num(1.25); + if let Some(NodeCertification::Certified) = certification_type { + log::debug!("Certified node detected, increasing amount due by 25%"); + amount_due *= U64F64::from_num(CERTIFIED_INCREASE_FACTOR); } // convert to balance object @@ -340,9 +338,7 @@ pub fn calculate_discount_tft( (amount_due, discount_received) } -pub fn calculate_cost_in_tft_from_units_usd( - cost_units_usd: u64, -) -> Result { +pub fn calculate_cost_in_tft_from_units_usd(cost_units_usd: u64) -> u64 { let avg_tft_price = pallet_tft_price::AverageTftPrice::::get(); // Guarantee tft price will never be lower than min tft price @@ -360,7 +356,7 @@ pub fn calculate_cost_in_tft_from_units_usd( let cost_tft = U64F64::from_num(cost_units_usd) / U64F64::from_num(tft_price_units_usd); // Multiply by the chain precision (7 decimals) - Ok((cost_tft * U64F64::from_num(10u64.pow(7))) + (cost_tft * U64F64::from_num(10u64.pow(7))) .round() - .to_num::()) + .to_num::() } 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 e8bee251e..bada34e30 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/grid_contract.rs @@ -223,9 +223,9 @@ impl Pallet { ContractID::::put(id); let now = Self::get_current_timestamp_in_secs(); - let mut contract_lock = types::ContractLock::default(); - contract_lock.lock_updated = now; - ContractLock::::insert(id, contract_lock); + let mut contract_payment_state = types::ContractPaymentState::default(); + contract_payment_state.last_updated_seconds = now; + ContractPaymentState::::insert(id, contract_payment_state); Ok(contract) } @@ -321,6 +321,10 @@ impl Pallet { } Self::update_contract_state(contract, &types::ContractState::Deleted(cause))?; + log::debug!( + "Billing for contract {} kicked in due to cancel request", + contract.contract_id + ); Self::bill_contract(contract.contract_id)?; Ok(().into()) @@ -329,6 +333,7 @@ impl Pallet { pub fn remove_contract(contract_id: u64) -> DispatchResultWithPostInfo { let contract = Contracts::::get(contract_id).ok_or(Error::::ContractNotExists)?; + log::debug!("removing contract {}", contract_id); match contract.contract_type.clone() { types::ContractData::NodeContract(mut node_contract) => { if node_contract.public_ips > 0 { @@ -370,13 +375,14 @@ impl Pallet { } }; - log::debug!("removing contract"); Contracts::::remove(contract_id); - ContractLock::::remove(contract_id); - + ContractPaymentState::::remove(contract_id); // Clean up contract from billing loop // This is the only place it should be done - log::debug!("cleaning up deleted contract from billing loop"); + log::debug!( + "cleaning up deleted contract {} from billing loop", + contract_id + ); Self::remove_contract_from_billing_loop(contract_id)?; Ok(().into()) @@ -404,7 +410,7 @@ impl Pallet { contract.state = state.clone(); Contracts::::insert(&contract.contract_id, contract.clone()); - // if the contract is a name contract, nothing to do left here + // if the contract is a name or rent contract, nothing to do left here match contract.contract_type { types::ContractData::NameContract(_) => return Ok(().into()), types::ContractData::RentContract(_) => return Ok(().into()), @@ -702,7 +708,14 @@ impl ChangeNode, InterfaceOf, SerialNumberOf> for &mut contract, &types::ContractState::Deleted(types::Cause::CanceledByUser), ); - let _ = Self::bill_contract(node_contract_id); + log::debug!( + "Billing for node contract {} kicked in due to node deletion", + contract.contract_id + ); + let res = Self::bill_contract(node_contract_id); + if let Err(e) = res { + log::error!("error in node_deleted hook while billing contract {:?}: {:?}. Contract could be in dirty state", node_contract_id, e); + } } } @@ -714,7 +727,14 @@ impl ChangeNode, InterfaceOf, SerialNumberOf> for &mut contract, &types::ContractState::Deleted(types::Cause::CanceledByUser), ); - let _ = Self::bill_contract(contract.contract_id); + log::debug!( + "Billing for rent contract {} kicked in due to node deletion", + contract.contract_id + ); + let res = Self::bill_contract(contract.contract_id); + if let Err(e) = res { + log::error!("error in node_deleted hook while billing contract id {:?}: {:?}. Contract could be in dirty state", rc_id, e); + } } } } @@ -725,10 +745,14 @@ impl ChangeNode, InterfaceOf, SerialNumberOf> for let node_power = pallet_tfgrid::NodePower::::get(node.id); if !node_power.is_standby() { if let Some(rc_id) = ActiveRentContractForNode::::get(node.id) { - let mut contract_lock = ContractLock::::get(rc_id); + let Some(mut contract_payment_state) = ContractPaymentState::::get(rc_id) else { + log::warn!("Contract payment state not exists for contract_id {}", rc_id); + return; + }; let now = Self::get_current_timestamp_in_secs(); - contract_lock.lock_updated = now; - ContractLock::::insert(rc_id, &contract_lock); + contract_payment_state.last_updated_seconds = now; + ContractPaymentState::::insert(rc_id, &contract_payment_state); + log::debug!("Rented node {} is back up, updated contract contract_payment_state for contract {}", node.id, rc_id); } } } diff --git a/substrate-node/pallets/pallet-smart-contract/src/lib.rs b/substrate-node/pallets/pallet-smart-contract/src/lib.rs index 8def850e4..e140c900e 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/lib.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/lib.rs @@ -63,7 +63,10 @@ pub mod pallet { use super::*; use frame_support::{ pallet_prelude::*, - traits::{Currency, Get, Hooks, LockIdentifier, LockableCurrency, OnUnbalanced}, + traits::{ + Currency, Get, Hooks, LockIdentifier, LockableCurrency, + OnUnbalanced, ReservableCurrency, + }, }; use frame_system::{ self as system, ensure_signed, @@ -83,8 +86,8 @@ pub mod pallet { <::Currency as Currency<::AccountId>>::Balance; pub type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; - pub const GRID_LOCK_ID: LockIdentifier = *b"gridlock"; + use tfchain_support::types::PublicIP; #[pallet::pallet] @@ -195,6 +198,11 @@ pub mod pallet { #[pallet::getter(fn dedicated_nodes_extra_fee)] pub type DedicatedNodesExtraFee = StorageMap<_, Blake2_128Concat, u32, u64, ValueQuery>; + #[pallet::storage] + #[pallet::getter(fn contract_payment_state)] + pub type ContractPaymentState = + StorageMap<_, Blake2_128Concat, u64, types::ContractPaymentState>, OptionQuery>; + #[pallet::config] pub trait Config: CreateSignedTransaction> @@ -207,7 +215,9 @@ pub mod pallet { + pallet_session::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type Currency: LockableCurrency; + type Currency: LockableCurrency + + ReservableCurrency + + Currency; /// Handler for the unbalanced decrement when slashing (burning collateral) type Burn: OnUnbalanced>; type StakingPoolAccount: Get; @@ -289,14 +299,14 @@ pub mod pallet { RentContractCanceled { contract_id: u64, }, - /// A Contract grace period is triggered + /// A Contract grace period is triggered due to overdarfted ContractGracePeriodStarted { contract_id: u64, node_id: u32, twin_id: u32, block_number: u64, }, - /// A Contract grace period was ended + /// A Contract grace period was ended due to overdarfted being settled ContractGracePeriodEnded { contract_id: u64, node_id: u32, @@ -328,6 +338,28 @@ pub mod pallet { node_id: u32, extra_fee: u64, }, + // A rent contract is waived due to node being in standby + RentWaived { + contract_id: u64, + }, + // A Contract grace Period is elapsed + ContractGracePeriodElapsed { + contract_id: u64, + grace_period: u64, + }, + // Overdafted incurred + ContractPaymentOverdrawn { + contract_id: u64, + timestamp: u64, + partially_billed_amount: BalanceOf, + overdraft: BalanceOf, + }, + // RewardDistributed + RewardDistributed { + contract_id: u64, + standard_rewards: BalanceOf, + additional_rewards: BalanceOf, + }, } #[pallet::error] @@ -384,6 +416,8 @@ pub mod pallet { WrongAuthority, UnauthorizedToChangeSolutionProviderId, UnauthorizedToSetExtraFee, + RewardDistributionError, + ContractPaymentStateNotExists, } #[pallet::genesis_config] @@ -515,8 +549,31 @@ pub mod pallet { origin: OriginFor, contract_id: u64, ) -> DispatchResultWithPostInfo { - let _account_id = ensure_signed(origin)?; - Self::bill_contract(contract_id) + let account_id = ensure_signed(origin)?; + log::debug!("Starting billing for contract_id: {:?}", contract_id); + + let res = Self::bill_contract(contract_id); + + let pays: Pays = if Self::is_validator(account_id) { + log::debug!("validator is exempt from fees"); + // Exempt fees for validators + Pays::No.into() + } else { + Pays::Yes.into() + }; + + match res { + Ok(mut info) => { + log::info!("successfully billed contract with id {:?}", contract_id,); + info.pays_fee = pays; + Ok(info) + } + Err(mut info) => { + log::warn!("failed to bill contract with id {:?}", contract_id); + info.post_info.pays_fee = pays; + Err(info) + } + } } #[pallet::call_index(11)] diff --git a/substrate-node/pallets/pallet-smart-contract/src/migrations/mod.rs b/substrate-node/pallets/pallet-smart-contract/src/migrations/mod.rs index 0c2c7bfa7..62cb15abc 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/migrations/mod.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/migrations/mod.rs @@ -5,3 +5,4 @@ pub mod v10; pub mod v11; pub mod v8; pub mod v9; +pub mod v12; diff --git a/substrate-node/pallets/pallet-smart-contract/src/migrations/types.rs b/substrate-node/pallets/pallet-smart-contract/src/migrations/types.rs index 89125d03e..ece8c6689 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/migrations/types.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/migrations/types.rs @@ -46,3 +46,20 @@ pub mod v11 { pub cycles: u16, } } + +pub mod v12 { + use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; + use scale_info::TypeInfo; + + #[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, Debug, TypeInfo, MaxEncodedLen, + )] + pub struct ContractPaymentState { + pub standard_reserve: BalanceOf, + pub additional_reserve: BalanceOf, + pub standard_overdraft: BalanceOf, + pub additional_overdraft: BalanceOf, + pub last_updated_seconds: u64, + pub cycles: u16, + } +} diff --git a/substrate-node/pallets/pallet-smart-contract/src/migrations/v12.rs b/substrate-node/pallets/pallet-smart-contract/src/migrations/v12.rs new file mode 100644 index 000000000..da7e5bf72 --- /dev/null +++ b/substrate-node/pallets/pallet-smart-contract/src/migrations/v12.rs @@ -0,0 +1,207 @@ +use crate::*; +use frame_support::{ + pallet_prelude::ValueQuery, + storage_alias, + traits::{LockableCurrency, OnRuntimeUpgrade}, + weights::Weight, + Blake2_128Concat, +}; +use log::{debug, info}; +use sp_core::Get; +use sp_runtime::traits::{Saturating, Zero}; +use sp_std::marker::PhantomData; + +#[cfg(feature = "try-runtime")] +use frame_support::ensure; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; +#[cfg(feature = "try-runtime")] +use sp_runtime::DispatchError; + +// Storage alias from ContractPaymentState v12 +#[storage_alias] +pub type ContractPaymentState = StorageMap< + Pallet, + Blake2_128Concat, + u64, + super::types::v12::ContractPaymentState>, + ValueQuery, +>; + +pub struct MigrateContractLockToContractPaymentState(pub PhantomData); + +impl OnRuntimeUpgrade for MigrateContractLockToContractPaymentState { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + validate_pallet_version::(types::StorageVersion::V11)?; + + let count = ContractLock::::iter().count(); + debug!( + "🏁 Smart Contract pallet {:?} ContractLock length before migration {:?}", + PalletVersion::::get(), + count + ); + + Ok(count.to_le_bytes().to_vec()) + } + + fn on_runtime_upgrade() -> Weight { + if PalletVersion::::get() == types::StorageVersion::V11 { + migrate_to_version_12::() + } else { + info!(" >>> Unused Smart Contract pallet V12 migration"); + Weight::zero() + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(count: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + validate_pallet_version::(types::StorageVersion::V12)?; + + let new_count = ContractPaymentState::::iter().count(); + let old_count = + usize::from_le_bytes(count.try_into().expect("slice with incorrect length")); + + if old_count != 0 { + debug!( + "🏁 Smart Contract pallet {:?} ContractPaymentState length after migration {:?}", + PalletVersion::::get(), + new_count + ); + ensure!( + new_count == old_count, + DispatchError::Other( + "Number of ContractPaymentState migrated does not match: {:?}" + ) + ); + } + + // Ensure that the ContractLock storage map is empty + let count = ContractLock::::iter().count(); + ensure!( + count == 0, + DispatchError::Other("ContractLock not empty after migration") + ); + + // Ensure that the balances Locks storage map is empty + let count = pallet_balances::Locks::::iter().count(); + ensure!( + count == 0, + DispatchError::Other("Locks not empty after migration") + ); + + check_contract_payment_state_v12::() + } +} + +#[cfg(feature = "try-runtime")] +fn validate_pallet_version( + expected_version: types::StorageVersion, +) -> Result<(), sp_runtime::TryRuntimeError> { + let current_version = PalletVersion::::get(); + debug!("current pallet version: {:?}", current_version); + ensure!( + current_version >= expected_version, + DispatchError::Other("Unexpected pallet version") + ); + Ok(()) +} + +pub fn migrate_to_version_12() -> frame_support::weights::Weight { + debug!( + " >>> Starting contract pallet migration, pallet version: {:?}", + PalletVersion::::get() + ); + + let mut total_reads = 0; + let mut total_writes = 0; + + let (r, w) = migrate_contract_lock_to_contract_payment_state::(); + total_reads.saturating_accrue(r); + total_writes.saturating_accrue(w); + + let (r, w) = remove_all_balances_locks::(); + total_reads.saturating_accrue(r); + total_writes.saturating_accrue(w); + + // Set the new storage version + PalletVersion::::put(types::StorageVersion::V12); + total_writes.saturating_inc(); + + T::DbWeight::get().reads_writes(total_reads, total_writes) +} + +fn migrate_contract_lock_to_contract_payment_state() -> (u64, u64) { + let mut reads = 0; + let mut writes = 0; + + for (contract_id, old_contract_lock) in ContractLock::::drain() { + reads.saturating_inc(); + writes.saturating_inc(); + + ContractPaymentState::::insert( + contract_id, + super::types::v12::ContractPaymentState { + standard_reserve: BalanceOf::::zero(), + additional_reserve: BalanceOf::::zero(), + standard_overdraft: old_contract_lock.amount_locked, + additional_overdraft: old_contract_lock.extra_amount_locked, + last_updated_seconds: old_contract_lock.lock_updated, + cycles: old_contract_lock.cycles, + }, + ); + writes.saturating_inc(); + }; + + (reads, writes) +} + +fn remove_all_balances_locks() -> (u64, u64) { + let mut reads = 0; + let mut writes = 0; + // Get only the accounts with locks + for (account_id, _) in pallet_balances::Locks::::iter() { + reads.saturating_inc(); + // Fetch all locks for the account + let locks = pallet_balances::Pallet::::locks(&account_id); + reads.saturating_inc(); + + // Remove each lock + for lock in locks { + pallet_balances::Pallet::::remove_lock(lock.id, &account_id); + reads.saturating_inc(); + writes.saturating_inc(); + } + } + + (reads, writes) +} + +#[cfg(feature = "try-runtime")] +pub fn check_contract_payment_state_v12() -> Result<(), sp_runtime::TryRuntimeError> { + debug!( + "🔎 Smart Contract pallet {:?} checking ContractPaymentState storage map START", + PalletVersion::::get() + ); + + for (contract_id, _) in Contracts::::iter() { + if !ContractPaymentState::::contains_key(contract_id) { + debug!( + " ⚠️ Contract (id: {}): no contract payment state found", + contract_id + ); + } + } + + debug!( + "🏁 Smart Contract pallet {:?} checking ContractPaymentState storage map END", + PalletVersion::::get() + ); + + debug!( + "👥 Smart Contract pallet to {:?} passes POST migrate checks ✅", + PalletVersion::::get() + ); + + Ok(()) +} diff --git a/substrate-node/pallets/pallet-smart-contract/src/migrations/v9.rs b/substrate-node/pallets/pallet-smart-contract/src/migrations/v9.rs index fc4c7661f..3a477bd5e 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/migrations/v9.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/migrations/v9.rs @@ -1,9 +1,9 @@ use crate::*; use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; -use log::{info, debug}; -use sp_runtime::Saturating; +use log::{debug, info}; use scale_info::prelude::string::String; use sp_core::Get; +use sp_runtime::Saturating; use sp_std::{marker::PhantomData, vec, vec::Vec}; #[cfg(feature = "try-runtime")] @@ -15,8 +15,9 @@ pub struct CleanStorageState(PhantomData); impl OnRuntimeUpgrade for CleanStorageState { fn on_runtime_upgrade() -> Weight { - if PalletVersion::::get() == types::StorageVersion::V8 || - PalletVersion::::get() == types::StorageVersion::V9 { + if PalletVersion::::get() == types::StorageVersion::V8 + || PalletVersion::::get() == types::StorageVersion::V9 + { info!("🔔 Starting Smart Contract pallet storage cleaning"); // Start a migration (this happens before on_initialize so it'll happen later in this // block, which should be good enough)... @@ -25,14 +26,15 @@ impl OnRuntimeUpgrade for CleanStorageState { } else { info!("⛔ Unused Smart Contract pallet V9 storage cleaning"); Weight::zero() - } + } } #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { info!("current pallet version: {:?}", PalletVersion::::get()); ensure!( - PalletVersion::::get() == types::StorageVersion::V8 || PalletVersion::::get() == types::StorageVersion::V9, + PalletVersion::::get() == types::StorageVersion::V8 + || PalletVersion::::get() == types::StorageVersion::V9, DispatchError::Other("Unexpected pallet version") ); @@ -56,20 +58,36 @@ pub fn check_pallet_smart_contract() { check_node_contract_resources::(); } -pub fn clean_pallet_smart_contract(current_stage: MigrationStage +pub fn clean_pallet_smart_contract( + current_stage: MigrationStage, ) -> (frame_support::weights::Weight, Option) { - info!("🧼 Cleaning Smart Contract pallet storage [{}/10]", current_stage); + info!( + "🧼 Cleaning Smart Contract pallet storage [{}/10]", + current_stage + ); match current_stage { 0 => (Weight::zero(), Some(current_stage + 1)), 1 => (clean_contracts::(), Some(current_stage + 1)), 2 => (clean_contracts_to_bill_at::(), Some(current_stage + 1)), 3 => (clean_active_node_contracts::(), Some(current_stage + 1)), - 4 => (clean_active_rent_contract_for_node::(), Some(current_stage + 1)), - 5 => (clean_contract_id_by_node_id_and_hash::(), Some(current_stage + 1)), - 6 => (clean_contract_id_by_name_registration::(), Some(current_stage + 1)), + 4 => ( + clean_active_rent_contract_for_node::(), + Some(current_stage + 1), + ), + 5 => ( + clean_contract_id_by_node_id_and_hash::(), + Some(current_stage + 1), + ), + 6 => ( + clean_contract_id_by_name_registration::(), + Some(current_stage + 1), + ), 7 => (clean_contract_lock::(), Some(current_stage + 1)), 8 => (clean_solution_providers::(), Some(current_stage + 1)), - 9 => (clean_contract_billing_information_by_id::(), Some(current_stage + 1)), + 9 => ( + clean_contract_billing_information_by_id::(), + Some(current_stage + 1), + ), // Last cleaning operation, set stage to none to stop migration 10 => { let weight = clean_node_contract_resources::(); @@ -178,7 +196,7 @@ fn check_node_contract(node_id: u32, contract_id: u64, deployment_has } // NodeContractResources - // Nothing to check here + // Nothing to check here // A node contract needs a call to report_contract_resources() to // have associated ressources in NodeContractResources storage map } else { @@ -191,7 +209,9 @@ fn check_node_contract(node_id: u32, contract_id: u64, deployment_has if deployment_hash == types::HexHash::default() { debug!( " ⚠️ Node Contract (id: {}) on node {}: deployment hash is default ({:?})", - contract_id, node_id, String::from_utf8_lossy(&deployment_hash) + contract_id, + node_id, + String::from_utf8_lossy(&deployment_hash) ); } } @@ -204,8 +224,7 @@ fn check_name_contract(contract_id: u64, name: &T::NameContractName) " ⚠️ Name Contract (id: {}): key (name: {:?}) not exists", contract_id, name ); - } - else if ctr_id != contract_id { + } else if ctr_id != contract_id { debug!( " ⚠️ Name Contract (id: {}): wrong contract (id: {}) in name registration map", contract_id, ctr_id @@ -382,7 +401,8 @@ pub fn check_contract_id_by_node_id_and_hash() { if pallet_tfgrid::Nodes::::get(node_id).is_none() { debug!( " ⚠️ ContractIDByNodeIDAndHash[node: {}, hash: {:?}]: node not exists", - node_id, String::from_utf8_lossy(&hash) + node_id, + String::from_utf8_lossy(&hash) ); } @@ -392,7 +412,7 @@ pub fn check_contract_id_by_node_id_and_hash() { if node_contract.deployment_hash != hash { debug!( " ⚠️ ContractIDByNodeIDAndHash[node: {}, hash: {:?}]: deployment hash ({:?}) on contract {} is not matching", - node_id, String::from_utf8_lossy(&hash), String::from_utf8_lossy(&node_contract.deployment_hash), contract_id, + node_id, String::from_utf8_lossy(&hash), String::from_utf8_lossy(&node_contract.deployment_hash), contract_id, ); } } @@ -406,7 +426,9 @@ pub fn check_contract_id_by_node_id_and_hash() { } else { debug!( " ⚠️ ContractIDByNodeIDAndHash[node: {}, hash: {:?}]: contract {} not exists", - node_id, String::from_utf8_lossy(&hash), contract_id + node_id, + String::from_utf8_lossy(&hash), + contract_id ); } } @@ -431,7 +453,7 @@ pub fn check_contract_id_by_name_registration() { if name_contract.name != name { debug!( " ⚠️ ContractIDByNameRegistration[name: {:?}]: name ({:?}) on contract {} is not matching", - String::from_utf8_lossy(&name.into()), String::from_utf8_lossy(&name_contract.name.into()), contract_id, + String::from_utf8_lossy(&name.into()), String::from_utf8_lossy(&name_contract.name.into()), contract_id, ); } } @@ -445,7 +467,8 @@ pub fn check_contract_id_by_name_registration() { } else { debug!( " ⚠️ ContractIDByNameRegistration[name: {:?}]: contract {} not exists", - String::from_utf8_lossy(&name.into()), contract_id + String::from_utf8_lossy(&name.into()), + contract_id ); } } @@ -464,7 +487,7 @@ pub fn check_contract_lock() { ); for (contract_id, _contract_lock) in ContractLock::::iter() { - if Contracts::::get(contract_id).is_none() { + if Contracts::::get(contract_id).is_none() { debug!( " ⚠️ ContractLock[contract: {}]: contract not exists", contract_id @@ -509,7 +532,8 @@ pub fn check_contract_billing_information_by_id() { PalletVersion::::get() ); - for (contract_id, _contract_billing_information) in ContractBillingInformationByID::::iter() { + for (contract_id, _contract_billing_information) in ContractBillingInformationByID::::iter() + { if let Some(c) = Contracts::::get(contract_id) { match c.contract_type { types::ContractData::NodeContract(_) => (), @@ -545,7 +569,7 @@ pub fn check_node_contract_resources() { if contract_resource.contract_id != contract_id { debug!( " ⚠️ NodeContractResources[contract: {}]: wrong contract id on resource ({})", - contract_id, contract_resource.contract_id + contract_id, contract_resource.contract_id ); } @@ -618,7 +642,13 @@ pub fn clean_contracts() -> frame_support::weights::Weight { T::DbWeight::get().reads_writes(r.saturating_add(2), w) } -fn clean_node_contract(node_id: u32, contract_id: u64, deployment_hash: types::HexHash, r: &mut u64, w: &mut u64) { +fn clean_node_contract( + node_id: u32, + contract_id: u64, + deployment_hash: types::HexHash, + r: &mut u64, + w: &mut u64, +) { if deployment_hash == types::HexHash::default() { Contracts::::remove(contract_id); (*w).saturating_inc(); @@ -693,9 +723,9 @@ pub fn clean_active_node_contracts() -> frame_support::weights::Weigh ActiveNodeContracts::::remove(node_id); w.saturating_inc(); } else { - contract_ids.retain(|contract_id| { + contract_ids.retain(|contract_id| { r.saturating_inc(); - Contracts::::get(contract_id).is_some() + Contracts::::get(contract_id).is_some() }); ActiveNodeContracts::::insert(node_id, contract_ids); w.saturating_inc(); @@ -921,4 +951,4 @@ pub fn clean_node_contract_resources() -> frame_support::weights::Wei ); T::DbWeight::get().reads_writes(r.saturating_add(2), w) -} \ No newline at end of file +} diff --git a/substrate-node/pallets/pallet-smart-contract/src/tests.rs b/substrate-node/pallets/pallet-smart-contract/src/tests.rs index 62460ab73..8fe7572e9 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/tests.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/tests.rs @@ -5,7 +5,7 @@ use crate::{ use frame_support::{ assert_noop, assert_ok, dispatch::Pays, - traits::{LockableCurrency, WithdrawReasons}, + traits::{BalanceStatus, Currency, LockableCurrency, ReservableCurrency, WithdrawReasons}, BoundedVec, }; use frame_system::{EventRecord, Phase, RawOrigin}; @@ -16,7 +16,10 @@ use pallet_tfgrid::{ }; use sp_core::{bounded_vec, H256}; use sp_runtime::{assert_eq_error_rate, traits::SaturatedConversion, Perbill, Percent}; -use sp_std::convert::{TryFrom, TryInto}; +use sp_std::{ + cmp::max, + convert::{TryFrom, TryInto}, +}; use substrate_fixed::types::U64F64; use tfchain_support::{ constants::time::{SECS_PER_BLOCK, SECS_PER_HOUR}, @@ -972,12 +975,14 @@ fn test_node_contract_billing_details() { ext.execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); let twin = TfgridModule::twins(2).unwrap(); - let initial_twin_balance = Balances::free_balance(&twin.account_id); + let initial_twin_balance = Balances::total_balance(&twin.account_id); assert_ok!(SmartContractModule::create_node_contract( RuntimeOrigin::signed(bob()), @@ -999,10 +1004,10 @@ fn test_node_contract_billing_details() { vec![contract_id] ); - let initial_total_issuance = Balances::total_issuance(); - // advance 25 cycles - for i in 0..25 { - let block_number = 11 + i * 10; + let initial_farmer_balance = Balances::free_balance(alice()); + // advance 24 cycles to reach reward distribution block + for i in 1..=DistributionFrequency::get() as u64 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -1011,47 +1016,71 @@ fn test_node_contract_billing_details() { run_to_block(block_number, Some(&mut pool_state)); } - let free_balance = Balances::free_balance(&twin.account_id); - let total_amount_billed = initial_twin_balance - free_balance; - info!("locked balance {:?}", total_amount_billed); + let twin_balance = Balances::total_balance(&twin.account_id); + let total_amount_billed = initial_twin_balance - twin_balance; + info!("current balance {:?}", twin_balance); + info!("total amount billed {:?}", total_amount_billed); - info!("total locked balance {:?}", total_amount_billed); + validate_distribution_rewards(initial_farmer_balance, total_amount_billed, 0, true, false); - let staking_pool_account_balance = Balances::free_balance(&get_staking_pool_account()); - info!( - "staking pool account balance, {:?}", - staking_pool_account_balance - ); + // amount unbilled should have been reset after a transfer between contract owner and farmer + let contract_billing_info = + SmartContractModule::contract_billing_information_by_id(contract_id); + assert_eq!(contract_billing_info.amount_unbilled, 0); + }); +} - // 5% is sent to the staking pool account - assert_eq!( - staking_pool_account_balance, - Perbill::from_percent(5) * total_amount_billed - ); +#[test] +fn test_node_contract_billing_works_for_non_existing_accounts() { + 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; - // 10% is sent to the foundation account - let pricing_policy = TfgridModule::pricing_policies(1).unwrap(); - let foundation_account_balance = Balances::free_balance(&pricing_policy.foundation_account); - assert_eq!( - foundation_account_balance, - Perbill::from_percent(10) * total_amount_billed - ); + TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); + + let twin = TfgridModule::twins(2).unwrap(); + let initial_twin_balance = Balances::total_balance(&twin.account_id); + + assert_ok!(SmartContractModule::create_node_contract( + RuntimeOrigin::signed(bob()), + node_id, + generate_deployment_hash(), + get_deployment_data(), + 1, + None + )); + let contract_id = 1; - // 50% is sent to the sales account - let sales_account_balance = Balances::free_balance(&pricing_policy.certified_sales_account); + push_contract_resources_used(contract_id); + push_nru_report_for_contract(contract_id, 10); + + // Ensure contract_id is stored at right billing loop index + let index = SmartContractModule::get_billing_loop_index_from_contract_id(contract_id); assert_eq!( - sales_account_balance, - Perbill::from_percent(50) * total_amount_billed + SmartContractModule::contract_to_bill_at_block(index), + vec![contract_id] ); - let total_issuance = Balances::total_issuance(); - // total issueance is now previous total - amount burned from contract billed (35%) - let burned_amount = Perbill::from_percent(35) * total_amount_billed; - assert_eq_error_rate!( - total_issuance, - initial_total_issuance - burned_amount as u64, - 1 - ); + let initial_farmer_balance = Balances::free_balance(alice()); + // advance 24 cycles to reach reward distribution block + for i in 1..=DistributionFrequency::get() as u64 { + let block_number = 1 + i * BillingFrequency::get(); + pool_state.write().should_call_bill_contract( + contract_id, + Ok(Pays::Yes.into()), + block_number, + ); + run_to_block(block_number, Some(&mut pool_state)); + } + + let twin_balance = Balances::total_balance(&twin.account_id); + let total_amount_billed = initial_twin_balance - twin_balance; + info!("current balance {:?}", twin_balance); + info!("total amount billed {:?}", total_amount_billed); + + validate_distribution_rewards(initial_farmer_balance, total_amount_billed, 0, false, false); // amount unbilled should have been reset after a transfer between contract owner and farmer let contract_billing_info = @@ -1060,21 +1089,68 @@ fn test_node_contract_billing_details() { }); } +#[test] +fn test_billing_node_contract_in_graceperiod_should_reset_unbilled_network_consumption_after_added_to_overdraft( +) { + 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(); + + 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); + push_nru_report_for_contract(contract_id, 10); + + // cycle 1 + // user does not have enough funds to pay + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 11); + run_to_block(11, Some(&mut pool_state)); + + let c1 = SmartContractModule::contracts(1).unwrap(); + assert_eq!(c1.state, types::ContractState::GracePeriod(11)); + + // contract payment should be overdrawn + let contract_payment_state = SmartContractModule::contract_payment_state(contract_id).unwrap(); + assert_ne!(contract_payment_state.get_overdraft(), 0); + + // amount unbilled should have been reset after adding the amount to the contract overdraft + let contract_billing_info = + SmartContractModule::contract_billing_information_by_id(contract_id); + assert_eq!(contract_billing_info.amount_unbilled, 0); + }); +} + #[test] fn test_node_contract_billing_details_with_solution_provider() { 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; prepare_solution_provider(dave()); + activate_billing_accounts(); TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); let twin = TfgridModule::twins(2).unwrap(); let initial_twin_balance = Balances::free_balance(&twin.account_id); - let initial_total_issuance = Balances::total_issuance(); + let initial_farmer_balance = Balances::free_balance(alice()); assert_ok!(SmartContractModule::create_node_contract( RuntimeOrigin::signed(bob()), @@ -1096,9 +1172,9 @@ fn test_node_contract_billing_details_with_solution_provider() { vec![contract_id] ); - // advance 25 cycles - for i in 0..25 { - let block_number = 11 + i * 10; + // advance 24 cycles to reach reward distribution block + for i in 1..=DistributionFrequency::get() as u64 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -1107,10 +1183,10 @@ fn test_node_contract_billing_details_with_solution_provider() { run_to_block(block_number, Some(&mut pool_state)); } - let free_balance = Balances::free_balance(&twin.account_id); - let total_amount_billed = initial_twin_balance - free_balance; + let total_balance = Balances::total_balance(&twin.account_id); + let total_amount_billed = initial_twin_balance - total_balance; - validate_distribution_rewards(initial_total_issuance, total_amount_billed, true); + validate_distribution_rewards(initial_farmer_balance, total_amount_billed, 0, true, false); // amount unbilled should have been reset after a transfer between contract owner and farmer let contract_billing_info = @@ -1213,12 +1289,10 @@ fn test_node_contract_billing_cycles() { check_report_cost(1, amount_due_1, 11, discount_received); let twin = TfgridModule::twins(twin_id).unwrap(); - let usable_balance = Balances::usable_balance(&twin.account_id); - let free_balance = Balances::free_balance(&twin.account_id); + let reserved_balance = Balances::reserved_balance(&twin.account_id); - let locked_balance = free_balance - usable_balance; assert_eq!( - locked_balance.saturated_into::(), + reserved_balance.saturated_into::(), amount_due_1 as u128 ); @@ -1237,12 +1311,11 @@ fn test_node_contract_billing_cycles() { check_report_cost(1, amount_due_3, 31, discount_received); let twin = TfgridModule::twins(twin_id).unwrap(); - let usable_balance = Balances::usable_balance(&twin.account_id); - let free_balance = Balances::free_balance(&twin.account_id); - let locked_balance = free_balance - usable_balance; + let reserved_balance = Balances::reserved_balance(&twin.account_id); + assert_eq!( - locked_balance.saturated_into::(), + reserved_balance.saturated_into::(), amount_due_1 as u128 + amount_due_2 as u128 + amount_due_3 as u128 ); }); @@ -1316,12 +1389,9 @@ fn test_node_multiple_contract_billing_cycles() { ); let twin = TfgridModule::twins(twin_id).unwrap(); - let usable_balance = Balances::usable_balance(&twin.account_id); - let free_balance = Balances::free_balance(&twin.account_id); - - let locked_balance = free_balance - usable_balance; + let reserved_balance = Balances::reserved_balance(&twin.account_id); assert_eq!( - locked_balance.saturated_into::(), + reserved_balance.saturated_into::(), amount_due_contract_1 as u128 + amount_due_contract_2 as u128 ); }); @@ -1333,6 +1403,8 @@ fn test_node_contract_billing_cycles_delete_node_cancels_contract() { ext.execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -1348,8 +1420,8 @@ fn test_node_contract_billing_cycles_delete_node_cancels_contract() { let contract_id = 1; let twin_id = 2; - for i in 0..5 { - let block_number = 11 + i * 10; + for i in 1..=5 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -1403,6 +1475,7 @@ fn test_node_contract_billing_cycles_delete_node_cancels_contract() { vec![].try_into().unwrap(); ips.try_push(public_ip).unwrap(); + log::debug!("events : {:?}", our_events); assert_eq!( our_events.contains(&record(MockEvent::SmartContractModule( SmartContractEvent::::IPsFreed { @@ -1446,8 +1519,8 @@ fn test_node_contract_only_public_ip_billing_cycles() { let contract_id = 1; let twin_id = 2; - for i in 0..5 { - let block_number = 11 + i * 10; + for i in 1..=5 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -1484,6 +1557,8 @@ fn test_node_contract_billing_cycles_cancel_contract_during_cycle_works() { ext.execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -1500,8 +1575,8 @@ fn test_node_contract_billing_cycles_cancel_contract_during_cycle_works() { let twin_id = 2; // 2 cycles for billing - for i in 0..2 { - let block_number = 11 + i * 10; + for i in 1..=2 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -1542,6 +1617,8 @@ fn test_node_contract_billing_cycles_cancel_contract_during_cycle_without_balanc ext.execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -1549,7 +1626,7 @@ fn test_node_contract_billing_cycles_cancel_contract_during_cycle_without_balanc let twin = TfgridModule::twins(2).unwrap(); let initial_twin_balance = Balances::free_balance(&twin.account_id); info!("initial twin balance: {:?}", initial_twin_balance); - let initial_total_issuance = Balances::total_issuance(); + let initial_farmer_balance = Balances::free_balance(alice()); assert_ok!(SmartContractModule::create_node_contract( RuntimeOrigin::signed(bob()), @@ -1580,18 +1657,24 @@ fn test_node_contract_billing_cycles_cancel_contract_during_cycle_without_balanc // Run halfway ish next cycle and cancel run_to_block(25, Some(&mut pool_state)); - let usable_balance = Balances::usable_balance(&twin.account_id); - let total_amount_billed = initial_twin_balance - usable_balance; + let free_balance = Balances::free_balance(&twin.account_id); + info!("free balance: {:?}", free_balance); + let total_amount_billed = initial_twin_balance - free_balance; + info!("total amount billed: {:?}", total_amount_billed); - let extrinsic_fee = 10000; + let leave = 1000; Balances::transfer( RuntimeOrigin::signed(bob()), - alice(), - initial_twin_balance - total_amount_billed - extrinsic_fee, + charlie(), + initial_twin_balance - total_amount_billed - leave, ) .unwrap(); - let usable_balance_before_canceling = Balances::usable_balance(&twin.account_id); + let usable_balance_before_canceling = Balances::free_balance(&twin.account_id); + info!( + "usable balance before canceling: {:?}", + usable_balance_before_canceling + ); assert_ne!(usable_balance_before_canceling, 0); assert_ok!(SmartContractModule::cancel_contract( @@ -1600,14 +1683,27 @@ fn test_node_contract_billing_cycles_cancel_contract_during_cycle_without_balanc )); // After canceling contract, and not being able to pay for the remainder of the cycle - // where the cancel was excecuted, the remaining balance should still be the same - let usable_balance_after_canceling = Balances::usable_balance(&twin.account_id); - assert_eq!( - usable_balance_after_canceling, - usable_balance_before_canceling + // where the cancel was excecuted, should deduct as much as possible from the user + let usable_balance_after_canceling = Balances::free_balance(&twin.account_id); + info!( + "usable balance after canceling: {:?}", + usable_balance_after_canceling + ); + info!( + "total amount billed: {:?}", + total_amount_billed + + (usable_balance_before_canceling - usable_balance_after_canceling) ); + assert_eq!(usable_balance_after_canceling, EXISTENTIAL_DEPOSIT); - validate_distribution_rewards(initial_total_issuance, total_amount_billed, false); + validate_distribution_rewards( + initial_farmer_balance, + total_amount_billed + + (usable_balance_before_canceling - usable_balance_after_canceling), + 0, + true, + false, + ); }); } @@ -1684,8 +1780,8 @@ fn test_restore_node_contract_in_grace_works() { )); let contract_id = 1; - for i in 0..6 { - let block_number = 11 + i * 10; + for i in 1..=6 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -1735,12 +1831,14 @@ fn test_node_contract_grace_period_cancels_contract_when_grace_period_ends_works ext.execute_with(|| { run_to_block(1, None); prepare_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); let twin = TfgridModule::twins(3).unwrap(); - let initial_total_issuance = Balances::total_issuance(); + let initial_farmer_balance = Balances::free_balance(alice()); let initial_twin_balance = Balances::free_balance(&twin.account_id); assert_ok!(SmartContractModule::create_node_contract( @@ -1785,24 +1883,33 @@ fn test_node_contract_grace_period_cancels_contract_when_grace_period_ends_works ); // grace period stops after 100 blocknumbers, so after 121 - for i in 1..11 { - let block_number = 21 + i * 10; + for i in 1..=10 { + let block_number = 21 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), block_number, ); + run_to_block(block_number, Some(&mut pool_state)); } - for i in 1..11 { - run_to_block(21 + i * 10, Some(&mut pool_state)); - } + // expect ContractGracePeriodElapsed event + let our_events = System::events(); + assert_eq!( + our_events.contains(&record(MockEvent::SmartContractModule( + SmartContractEvent::::ContractGracePeriodElapsed { + contract_id, + grace_period: GracePeriod::get(), + } + ))), + true + ); // The user's total free balance should be distributed let free_balance = Balances::free_balance(&twin.account_id); let total_amount_billed = initial_twin_balance - free_balance; - validate_distribution_rewards(initial_total_issuance, total_amount_billed, false); + validate_distribution_rewards(initial_farmer_balance, total_amount_billed, 0, true, false); let c1 = SmartContractModule::contracts(contract_id); assert_eq!(c1, None); @@ -1845,7 +1952,7 @@ fn test_name_contract_billing() { let balance = Balances::free_balance(&twin.account_id); let second_elapsed = BillingFrequency::get() * SECS_PER_BLOCK; let (contract_cost, discount_level) = contract - .calculate_contract_cost_tft(balance, second_elapsed) + .calculate_contract_cost_tft(balance, second_elapsed, None) .unwrap(); // the contractbill event should look like: @@ -1866,6 +1973,18 @@ fn test_name_contract_billing() { contract_bill_event ))) ); + // advance 23 more cycles to reach reward distribution block + for i in 1..=23 { + let block_number = 11 + i * BillingFrequency::get(); + pool_state.write().should_call_bill_contract( + contract_id, + Ok(Pays::Yes.into()), + block_number, + ); + run_to_block(block_number, Some(&mut pool_state)); + } + let total_contract_cost = contract_cost * 24; + validate_distribution_rewards(0, total_contract_cost, 0, false, true) }); } @@ -1962,12 +2081,75 @@ fn test_rent_contract_billing() { }); } +#[test] +fn test_rent_contract_on_standby_node_rent_waived_and_cancel_works() { + let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); + ext.execute_with(|| { + run_to_block(1, None); + prepare_dedicated_farm_and_node(); + let node_id = 1; + + // switch node to standby at block 1 + assert_ok!(TfgridModule::change_power_state( + RuntimeOrigin::signed(alice()), + tfchain_support::types::Power::Down + )); + + TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); + + assert_ok!(SmartContractModule::create_rent_contract( + RuntimeOrigin::signed(bob()), + node_id, + None + )); + let contract_id = 1; + + let contract = SmartContractModule::contracts(contract_id).unwrap(); + let rent_contract = types::RentContract { node_id }; + assert_eq!( + contract.contract_type, + types::ContractData::RentContract(rent_contract) + ); + + // go to end of cycle 1 [1-11] and expect a call to bill_contract() + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 11); + run_to_block(11, Some(&mut pool_state)); + + // expect RentWaived event + let our_events = System::events(); + assert_eq!( + our_events.contains(&record(MockEvent::SmartContractModule( + SmartContractEvent::::RentWaived { contract_id } + ))), + true + ); + // cancel contract + assert_ok!(SmartContractModule::cancel_contract( + RuntimeOrigin::signed(bob()), + contract_id + )); + let our_events = System::events(); + + // expect ContractCanceled event + assert_eq!( + our_events.contains(&record(MockEvent::SmartContractModule( + SmartContractEvent::::RentContractCanceled { contract_id } + ))), + true + ); + }); +} + #[test] fn test_rent_contract_billing_cancel_should_bill_reserved_balance() { let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); ext.execute_with(|| { run_to_block(1, None); prepare_dedicated_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -1991,25 +2173,25 @@ fn test_rent_contract_billing_cancel_should_bill_reserved_balance() { .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 11); run_to_block(11, Some(&mut pool_state)); - let (amount_due_as_u128, discount_received) = calculate_tft_cost(contract_id, 2, 10); - assert_ne!(amount_due_as_u128, 0); + let (amount_due_1_as_u128, discount_received) = calculate_tft_cost(contract_id, 2, 10); + assert_ne!(amount_due_1_as_u128, 0); check_report_cost( contract_id, - amount_due_as_u128, + amount_due_1_as_u128, 11, discount_received.clone(), ); let twin = TfgridModule::twins(2).unwrap(); - let usable_balance = Balances::usable_balance(&twin.account_id); + let total_balance = Balances::total_balance(&twin.account_id); let free_balance = Balances::free_balance(&twin.account_id); - assert_ne!(usable_balance, free_balance); + assert_ne!(total_balance, free_balance); run_to_block(13, Some(&mut pool_state)); // cancel contract // it will bill before removing the contract and it should bill all // reserved balance - let (amount_due_as_u128, discount_received) = calculate_tft_cost(contract_id, 2, 2); + let (amount_due_2_as_u128, discount_received) = calculate_tft_cost(contract_id, 2, 2); assert_ok!(SmartContractModule::cancel_contract( RuntimeOrigin::signed(bob()), contract_id @@ -2020,13 +2202,133 @@ fn test_rent_contract_billing_cancel_should_bill_reserved_balance() { assert_ne!(usable_balance, 0); Balances::transfer(RuntimeOrigin::signed(bob()), alice(), usable_balance).unwrap(); - // Last amount due is the same as the first one - assert_ne!(amount_due_as_u128, 0); - check_report_cost(contract_id, amount_due_as_u128, 13, discount_received); + // Last amount due is not the same as the first one + assert_ne!(amount_due_1_as_u128, amount_due_2_as_u128); + check_report_cost(contract_id, amount_due_2_as_u128, 13, discount_received); - let usable_balance = Balances::usable_balance(&twin.account_id); + let total_balance = Balances::total_balance(&twin.account_id); let free_balance = Balances::free_balance(&twin.account_id); - assert_eq!(usable_balance, free_balance); + assert_eq!(total_balance, free_balance); + }); +} + +#[test] +fn test_rent_contract_overdrawn_and_partial_bill() { + let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); + ext.execute_with(|| { + run_to_block(1, None); + prepare_dedicated_farm_and_node(); + activate_billing_accounts(); + + let node_id = 1; + + TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); + + assert_ok!(SmartContractModule::create_rent_contract( + RuntimeOrigin::signed(charlie()), + node_id, + None + )); + let contract_id = 1; + + let twin = TfgridModule::twins(3).unwrap(); + let initial_reservable_balance = + Balances::usable_balance(&twin.account_id) - EXISTENTIAL_DEPOSIT; + + let contract = SmartContractModule::contracts(contract_id).unwrap(); + let rent_contract = types::RentContract { node_id }; + assert_eq!( + contract.contract_type, + types::ContractData::RentContract(rent_contract) + ); + + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 11); + run_to_block(11, Some(&mut pool_state)); + + let (amount_due_per_cycle, _) = calculate_tft_cost(contract_id, 2, 10); + assert_ne!(amount_due_per_cycle, 0); + + // expect contractPaymentOverdarwn event with partially billed amount + let our_events = System::events(); + assert_eq!( + our_events.contains(&record(MockEvent::SmartContractModule( + SmartContractEvent::::ContractPaymentOverdrawn { + contract_id: contract_id, + timestamp: get_timestamp_in_seconds_for_block(11), + partially_billed_amount: initial_reservable_balance, + overdraft: amount_due_per_cycle - initial_reservable_balance + } + ))), + true + ); + + let contract_payment_state = SmartContractModule::contract_payment_state(contract_id).unwrap(); + assert_eq!( + contract_payment_state.get_reserve(), + initial_reservable_balance + ); + assert_eq!( + contract_payment_state.get_overdraft(), + amount_due_per_cycle - initial_reservable_balance + ); + + let free_balance = Balances::free_balance(&twin.account_id); + assert_eq!(free_balance, EXISTENTIAL_DEPOSIT); + + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 21); + run_to_block(21, Some(&mut pool_state)); + + // expect contractPaymentOverdarwn event with no partially billed amount + let our_events = System::events(); + assert_eq!( + our_events.contains(&record(MockEvent::SmartContractModule( + SmartContractEvent::::ContractPaymentOverdrawn { + contract_id: contract_id, + timestamp: get_timestamp_in_seconds_for_block(21), + partially_billed_amount: 0, + overdraft: amount_due_per_cycle + } + ))), + true + ); + let contract_payment_state = SmartContractModule::contract_payment_state(contract_id).unwrap(); + assert_eq!( + contract_payment_state.get_reserve(), + initial_reservable_balance + ); + assert_eq!( + contract_payment_state.get_overdraft(), + amount_due_per_cycle * 2 - initial_reservable_balance + ); + let should_have_next_cycle = amount_due_per_cycle * 3 - initial_reservable_balance; + + // transfer some balance to the owner of the contract to trigger the grace period to stop + Balances::transfer( + RuntimeOrigin::signed(bob()), + charlie(), + should_have_next_cycle, + ) + .unwrap(); + + pool_state + .write() + .should_call_bill_contract(contract_id, Ok(Pays::Yes.into()), 31); + run_to_block(31, Some(&mut pool_state)); + + let contract_payment_state = SmartContractModule::contract_payment_state(contract_id).unwrap(); + assert_eq!( + contract_payment_state.get_reserve(), + amount_due_per_cycle * 3 + ); + assert_eq!(contract_payment_state.get_overdraft(), 0); + + // contract state should be Created + let c1 = SmartContractModule::contracts(contract_id).unwrap(); + assert_eq!(c1.state, types::ContractState::Created); }); } @@ -2036,6 +2338,8 @@ fn test_rent_contract_canceled_mid_cycle_should_bill_for_remainder() { ext.execute_with(|| { run_to_block(1, None); prepare_dedicated_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -2055,11 +2359,9 @@ fn test_rent_contract_canceled_mid_cycle_should_bill_for_remainder() { ); let twin = TfgridModule::twins(2).unwrap(); - let usable_balance = Balances::usable_balance(&twin.account_id); - let free_balance = Balances::free_balance(&twin.account_id); - let locked_balance = free_balance - usable_balance; - info!("locked balance: {:?}", locked_balance); + let reserved_balance = Balances::reserved_balance(&twin.account_id); + info!("reserved balance: {:?}", reserved_balance); run_to_block(8, Some(&mut pool_state)); // Calculate the cost for 7 blocks of runtime (created a block 1, canceled at block 8) @@ -2077,11 +2379,10 @@ fn test_rent_contract_canceled_mid_cycle_should_bill_for_remainder() { discount_received.clone(), ); - // Twin should have no more locked balance + // Twin should have no more reserved balance let twin = TfgridModule::twins(2).unwrap(); - let usable_balance = Balances::usable_balance(&twin.account_id); - let free_balance = Balances::free_balance(&twin.account_id); - assert_eq!(usable_balance, free_balance); + let reserved_balance = Balances::reserved_balance(&twin.account_id); + assert_eq!(reserved_balance, 0); }); } @@ -2134,9 +2435,11 @@ fn test_create_rent_contract_and_node_contract_excludes_node_contract_from_billi // Event 3: Rent contract created // Event 4: Node Contract created // Event 5: Updated resources contract - // Event 6: Balances locked + // Event 6: Balances Reserved // Event 7: Contract Billed // => no Node Contract billed event + log::debug!("our_events: {:?}", our_events); + assert_eq!(our_events.len(), 7); }); } @@ -2146,6 +2449,8 @@ fn test_rent_contract_canceled_due_to_out_of_funds_should_cancel_node_contracts_ let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); ext.execute_with(|| { prepare_dedicated_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; run_to_block(1, None); @@ -2158,7 +2463,7 @@ fn test_rent_contract_canceled_due_to_out_of_funds_should_cancel_node_contracts_ )); let rent_contract_id = 1; - run_to_block(2, None); + run_to_block(2, Some(&mut pool_state)); assert_ok!(SmartContractModule::create_node_contract( RuntimeOrigin::signed(charlie()), @@ -2172,8 +2477,8 @@ fn test_rent_contract_canceled_due_to_out_of_funds_should_cancel_node_contracts_ push_contract_resources_used(node_contract_id); // run 10 cycles - for i in 0..10 { - let block_number = 11 + i * 10; + for i in 1..=10 { + let block_number = 1 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( rent_contract_id, Ok(Pays::Yes.into()), @@ -2198,7 +2503,7 @@ fn test_rent_contract_canceled_due_to_out_of_funds_should_cancel_node_contracts_ run_to_block(end_grace_block_number, Some(&mut pool_state)); let our_events = System::events(); - assert_eq!(our_events.len(), 21); + assert_eq!(our_events.len(), 26); for e in our_events.clone() { log::info!("event: {:?}", e); @@ -2228,7 +2533,7 @@ fn test_rent_contract_canceled_due_to_out_of_funds_should_cancel_node_contracts_ ); assert_eq!( - our_events[19], + our_events[24], record(MockEvent::SmartContractModule(SmartContractEvent::< TestRuntime, >::NodeContractCanceled { @@ -2238,7 +2543,7 @@ fn test_rent_contract_canceled_due_to_out_of_funds_should_cancel_node_contracts_ })) ); assert_eq!( - our_events[20], + our_events[25], record(MockEvent::SmartContractModule(SmartContractEvent::< TestRuntime, >::RentContractCanceled { @@ -2264,7 +2569,7 @@ fn test_create_rent_contract_and_node_contract_with_ip_billing_works() { )); let rent_contract_id = 1; - run_to_block(2, None); + run_to_block(2, Some(&mut pool_state)); assert_ok!(SmartContractModule::create_node_contract( RuntimeOrigin::signed(bob()), @@ -2456,6 +2761,8 @@ fn test_restore_rent_contract_and_node_contracts_in_grace_works() { assert_eq!(c1.state, types::ContractState::GracePeriod(11)); let our_events = System::events(); + log::debug!("Events: {:?}", our_events); + assert_eq!( our_events[5], record(MockEvent::SmartContractModule(SmartContractEvent::< @@ -2522,9 +2829,10 @@ fn test_restore_rent_contract_and_node_contracts_in_grace_works() { assert_eq!(c1.state, types::ContractState::Created); let our_events = System::events(); + log::debug!("Events: {:?}", our_events); assert_eq!( - our_events[8], + our_events[12], record(MockEvent::SmartContractModule(SmartContractEvent::< TestRuntime, >::ContractGracePeriodEnded { @@ -2534,7 +2842,7 @@ fn test_restore_rent_contract_and_node_contracts_in_grace_works() { })) ); assert_eq!( - our_events[9], + our_events[13], record(MockEvent::SmartContractModule(SmartContractEvent::< TestRuntime, >::ContractGracePeriodEnded { @@ -2552,6 +2860,8 @@ fn test_rent_contract_grace_period_cancels_contract_when_grace_period_ends_works ext.execute_with(|| { run_to_block(1, None); prepare_dedicated_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -2585,9 +2895,9 @@ fn test_rent_contract_grace_period_cancels_contract_when_grace_period_ends_works true ); - // run 9 more cycles - for i in 0..10 { - let block_number = 21 + i * 10; + // advance 10 more cycles since the GracePeriod is 100 blocks and the BillingFrequency(cycle) is 10 blocks + for i in 1..=10 { + let block_number = 11 + i * BillingFrequency::get(); pool_state.write().should_call_bill_contract( contract_id, Ok(Pays::Yes.into()), @@ -2616,6 +2926,8 @@ fn test_rent_contract_and_node_contract_canceled_when_node_is_deleted_works() { ext.execute_with(|| { run_to_block(1, None); prepare_dedicated_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); @@ -3508,53 +3820,163 @@ fn test_cu_calculation() { } #[test] -fn test_lock() { +fn test_reserve_and_unreserve() { new_test_ext().execute_with(|| { - let usable_balance = Balances::usable_balance(&bob()); - let free_balance = Balances::free_balance(&bob()); + let total_balance = Balances::total_balance(&bob()); + let initial_free_balance = Balances::free_balance(&bob()); + let initial_reserved_balance = Balances::reserved_balance(&bob()); + log::debug!("Total balance: {}", total_balance); + log::debug!("Initial free balance: {}", initial_free_balance); + log::debug!("Initial reserved balance: {}", initial_reserved_balance); - // should be equal since no activity and no locks - assert_eq!(usable_balance, free_balance); + // should be equal since no activity and no reserves + assert_eq!(initial_reserved_balance, 0); - let id: u64 = 1; - // Try to lock less than EXISTENTIAL_DEPOSIT should fail - Balances::set_lock(id.to_be_bytes(), &bob(), 100, WithdrawReasons::all()); + // Try to reserve some amount should succeed + let res = Balances::reserve(&bob(), 100); - // usable balance should now return free balance - EXISTENTIAL_DEPOSIT cause there was some activity - let usable_balance = Balances::usable_balance(&bob()); + assert_eq!(res.is_ok(), true); + + // free balance should be decreased by 100 let free_balance = Balances::free_balance(&bob()); - assert_eq!(usable_balance, free_balance - EXISTENTIAL_DEPOSIT); + let expected_free_balance = initial_free_balance - 100; + assert_eq!(free_balance, expected_free_balance); + + // reserving all free balance shouldn't succeed + let to_reserve = free_balance; + assert_eq!(Balances::can_reserve(&bob(), to_reserve), false); + // Try to reserve all free balance + let res = Balances::reserve(&bob(), to_reserve); + assert_eq!(res.is_err(), true); + // balance still the same + assert_eq!(free_balance, expected_free_balance); - // ----- INITIAL ------ // - // Try to lock more than EXISTENTIAL_DEPOSIT should succeed - let to_lock = 100 + EXISTENTIAL_DEPOSIT; + // Try to reserve all reservable balance should succeed + let to_reserve = crate::pallet::Pallet::::get_usable_balance(&bob()); - Balances::set_lock(id.to_be_bytes(), &bob(), to_lock, WithdrawReasons::all()); + let res = Balances::reserve(&bob(), to_reserve); + assert_eq!(res.is_ok(), true); - // usable balance should now be free_balance - to_lock cause there was some activity - let usable_balance = Balances::usable_balance(&bob()); let free_balance = Balances::free_balance(&bob()); - assert_eq!(usable_balance, free_balance - to_lock); + let expected_reserved_balance = initial_free_balance - (100 + to_reserve); + assert_eq!(free_balance, expected_reserved_balance); - // ----- UPDATE ------ // - // updating a lock should succeed - let to_lock = 500 + EXISTENTIAL_DEPOSIT; + let reserved_balance = Balances::reserved_balance(&bob()); + assert_eq!(reserved_balance, initial_free_balance - EXISTENTIAL_DEPOSIT); - Balances::set_lock(id.to_be_bytes(), &bob(), to_lock, WithdrawReasons::all()); + // reservable balance should be 0 + assert_eq!( + crate::pallet::Pallet::::get_usable_balance(&bob()), + 0 + ); - // usable balance should now be free_balance - to_lock cause there was some activity - let usable_balance = Balances::usable_balance(&bob()); - let free_balance = Balances::free_balance(&bob()); - assert_eq!(usable_balance, free_balance - to_lock); + // unreserve should succeed without a remainder + let remainder = Balances::unreserve(&bob(), reserved_balance); + assert_eq!(remainder, 0); + // user balance now should be the same as initial + assert_eq!(Balances::free_balance(&bob()), initial_free_balance) + }) +} - // ----- UNLOCK ------ // - // Unlock should work - Balances::remove_lock(id.to_be_bytes(), &bob()); +#[test] +fn test_reserve_while_lock_exists() { + new_test_ext().execute_with(|| { + let total_balance = Balances::total_balance(&bob()); + let initial_free_balance = Balances::free_balance(&bob()); + let initial_reserved_balance = Balances::reserved_balance(&bob()); + log::debug!("Total balance: {}", total_balance); + log::debug!("Initial free balance: {}", initial_free_balance); + log::debug!("Initial reserved balance: {}", initial_reserved_balance); + + // should be equal since no activity and no reserves + assert_eq!(initial_reserved_balance, 0); + // Try to lock and reserve some amount should succeed + let id: [u8; 8] = *b"my_lock1"; + let locked_amount = initial_free_balance - 200100; + let reserved_amount = 200000; + let reservable_before = crate::pallet::Pallet::::get_usable_balance(&bob()); + log::info!("Reservable before: {}", reservable_before); + Balances::set_lock(id, &bob(), locked_amount, WithdrawReasons::all()); + let _ = Balances::reserve(&bob(), reserved_amount); + let reservable_after = crate::pallet::Pallet::::get_usable_balance(&bob()); + log::info!("Reservable after: {}", reservable_after); + + if locked_amount <= EXISTENTIAL_DEPOSIT { + assert_eq!(reservable_after + reserved_amount, reservable_before); + } else { + assert_ne!(reservable_after, reservable_before); + assert_eq!(Balances::can_reserve(&bob(), reservable_before), false); + } - // usable balance should now be free_balance cause there are no locks - let usable_balance = Balances::usable_balance(&bob()); - let free_balance = Balances::free_balance(&bob()); - assert_eq!(usable_balance, free_balance); + assert_eq!(Balances::can_reserve(&bob(), reservable_after), true); + + assert_eq!( + reservable_after, + initial_free_balance + .saturating_sub(max(locked_amount, EXISTENTIAL_DEPOSIT) + reserved_amount) + ); + + // reserve all reservable balance should succeed + let res = Balances::reserve(&bob(), reservable_after); + assert_eq!(res.is_ok(), true); + + // transfer all reserved balance should succeed + let res = Balances::repatriate_reserved( + &bob(), + &alice(), + reservable_after + reserved_amount, + BalanceStatus::Free, + ); + assert_eq!(res.is_ok(), true); + match res { + Ok(remainder) => assert_eq!(remainder, 0), + Err(_) => assert!(false), + } + + // reserved balance should be 0 + assert_eq!(Balances::reserved_balance(&bob()), 0); + + // reservable balance should be 0 + assert_eq!( + crate::pallet::Pallet::::get_usable_balance(&bob()), + 0 + ); + // user balance now should be only the max of locked_amount and EXISTENTIAL_DEPOSIT + assert_eq!( + Balances::free_balance(&bob()), + max(locked_amount, EXISTENTIAL_DEPOSIT) + ); + }) +} + +#[test] +fn test_reserve_and_transfer_reserved() { + new_test_ext().execute_with(|| { + let total_balance = Balances::total_balance(&bob()); + let initial_free_balance = Balances::free_balance(&bob()); + let initial_reserved_balance = Balances::reserved_balance(&bob()); + log::debug!("Total balance: {}", total_balance); + log::debug!("Initial free balance: {}", initial_free_balance); + log::debug!("Initial reserved balance: {}", initial_reserved_balance); + + // Try to reserve all reservable balance should succeed + let to_reserve = crate::pallet::Pallet::::get_usable_balance(&bob()); + + let res = Balances::reserve(&bob(), to_reserve); + assert_eq!(res.is_ok(), true); + + let res = Balances::repatriate_reserved(&bob(), &alice(), to_reserve, BalanceStatus::Free); + assert_eq!(res.is_ok(), true); + match res { + Ok(remainder) => assert_eq!(remainder, 0), + Err(_) => assert!(false), + } + + // reserved balance should be 0 + assert_eq!(Balances::reserved_balance(&bob()), 0); + + // user balance now should be only the existential deposit + assert_eq!(Balances::free_balance(&bob()), EXISTENTIAL_DEPOSIT) }) } @@ -3891,6 +4313,8 @@ fn test_set_dedicated_node_extra_fee_and_create_rent_contract_billing_works() { let (mut ext, mut pool_state) = new_test_ext_with_pool_state(0); ext.execute_with(|| { prepare_farm_and_node(); + activate_billing_accounts(); + let node_id = 1; let start_block = 1; @@ -3898,7 +4322,7 @@ fn test_set_dedicated_node_extra_fee_and_create_rent_contract_billing_works() { TFTPriceModule::set_prices(RuntimeOrigin::signed(alice()), 50, 101).unwrap(); - let initial_total_issuance = Balances::total_issuance(); + let initial_farmer_balance = Balances::free_balance(alice()); // Get daves's twin let twin = TfgridModule::twins(4).unwrap(); let initial_twin_balance = Balances::free_balance(&twin.account_id); @@ -3948,7 +4372,10 @@ fn test_set_dedicated_node_extra_fee_and_create_rent_contract_billing_works() { Ok(Pays::Yes.into()), block_number, ); + log::debug!("i {} after pool block_number: {}", i, block_number); + run_to_block(block_number, Some(&mut pool_state)); + log::debug!("i {} after run block_number: {}", i, block_number); // check why aggregating seconds elapsed is giving different results let elapsed_time_in_secs = BillingFrequency::get() * SECS_PER_BLOCK; @@ -3956,14 +4383,13 @@ fn test_set_dedicated_node_extra_fee_and_create_rent_contract_billing_works() { // aggregate rent contract cost let free_balance = Balances::free_balance(&twin.account_id); let (contract_cost_tft, _) = rent_contract - .calculate_contract_cost_tft(free_balance, elapsed_time_in_secs) + .calculate_contract_cost_tft(free_balance, elapsed_time_in_secs, None) .unwrap(); rent_contract_cost_tft += contract_cost_tft; // aggregate extra fee cost - extra_fee_cost_tft += rent_contract - .calculate_extra_fee_cost_tft(node_id, elapsed_time_in_secs) - .unwrap(); + extra_fee_cost_tft += + rent_contract.calculate_extra_fee_cost_tft(node_id, elapsed_time_in_secs); } let then = SmartContractModule::get_current_timestamp_in_secs(); @@ -3991,7 +4417,13 @@ fn test_set_dedicated_node_extra_fee_and_create_rent_contract_billing_works() { rent_contract_cost_tft + extra_fee_cost_tft ); - validate_distribution_rewards(initial_total_issuance, rent_contract_cost_tft, false); + validate_distribution_rewards( + initial_farmer_balance, + rent_contract_cost_tft, + extra_fee_cost_tft, + true, + false, + ); }) } @@ -4026,7 +4458,7 @@ macro_rules! test_calculate_discount { amount_due, seconds_elapsed, balance.round().to_num::(), - NodeCertification::Diy, + None, ); assert_eq!( @@ -4057,11 +4489,13 @@ test_calculate_discount! { // ---------------------------- // fn validate_distribution_rewards( - initial_total_issuance: u64, - total_amount_billed: u64, - had_solution_provider: bool, + initial_farmer_balance: u64, + standard_fees_billed: u64, + extra_fees_billed: u64, + had_existential_deposit: bool, + is_name_contract: bool, ) { - info!("total amount billed {:?}", total_amount_billed); + info!("total amount billed {:?}", standard_fees_billed); let staking_pool_account_balance = Balances::free_balance(&get_staking_pool_account()); info!( @@ -4069,52 +4503,39 @@ fn validate_distribution_rewards( staking_pool_account_balance ); - // 5% is sent to the staking pool account - assert_eq_error_rate!( + // 10% is sent to the staking pool account + assert_eq!( staking_pool_account_balance, - Perbill::from_percent(5) * total_amount_billed, - 6 + (Perbill::from_percent(10) * standard_fees_billed) + + if had_existential_deposit { + EXISTENTIAL_DEPOSIT + } else { + 0 + } ); - - // 10% is sent to the foundation account + let foundation_percent = if is_name_contract { 90 } else { 40 }; + // 40% is sent to the foundation account let pricing_policy = TfgridModule::pricing_policies(1).unwrap(); let foundation_account_balance = Balances::free_balance(&pricing_policy.foundation_account); assert_eq!( foundation_account_balance, - Perbill::from_percent(10) * total_amount_billed + (Perbill::from_percent(foundation_percent) * standard_fees_billed) + + if had_existential_deposit { + EXISTENTIAL_DEPOSIT + } else { + 0 + } ); - - if had_solution_provider { - // 40% is sent to the sales account - let sales_account_balance = Balances::free_balance(&pricing_policy.certified_sales_account); - assert_eq!( - sales_account_balance, - Perbill::from_percent(40) * total_amount_billed - ); - - // 10% is sent to the solution provider - let solution_provider = SmartContractModule::solution_providers(1).unwrap(); - let solution_provider_1_balance = - Balances::free_balance(solution_provider.providers[0].who.clone()); - info!("solution provider b: {:?}", solution_provider_1_balance); - assert_ne!(solution_provider_1_balance, 0); - } else { - // 50% is sent to the sales account - let sales_account_balance = Balances::free_balance(&pricing_policy.certified_sales_account); - assert_eq!( - sales_account_balance, - Perbill::from_percent(50) * total_amount_billed + if !is_name_contract { + // get alice balance + let farmer_balance = Balances::free_balance(&alice()); + let farmer_amount = Perbill::from_percent(50) * standard_fees_billed; + assert_eq_error_rate!( + farmer_balance, + initial_farmer_balance + farmer_amount + extra_fees_billed, + 5 ); } - - let total_issuance = Balances::total_issuance(); - // total issueance is now previous total - amount burned from contract billed (35%) - let burned_amount = Perbill::from_percent(35) * total_amount_billed; - assert_eq_error_rate!( - total_issuance, - initial_total_issuance - burned_amount as u64, - 1 - ); } fn push_nru_report_for_contract(contract_id: u64, block_number: u64) { @@ -4191,8 +4612,9 @@ fn calculate_tft_cost(contract_id: u64, twin_id: u32, blocks: u64) -> (u64, type let twin = TfgridModule::twins(twin_id).unwrap(); let b = Balances::free_balance(&twin.account_id); let contract = SmartContractModule::contracts(contract_id).unwrap(); - let (amount_due, discount_received) = - contract.calculate_contract_cost_tft(b, blocks * 6).unwrap(); + let (amount_due, discount_received) = contract + .calculate_contract_cost_tft(b, blocks * 6, None) + .unwrap(); (amount_due, discount_received) } @@ -4537,3 +4959,15 @@ fn get_service_contract() -> types::ServiceContract { fn get_timestamp_in_seconds_for_block(block_number: u64) -> u64 { 1628082000 + (6 * block_number) } + +fn activate_billing_accounts() { + let pricing_policy = TfgridModule::pricing_policies(1).unwrap(); + let foundation_account = pricing_policy.foundation_account; + let staking_pool_account = get_staking_pool_account(); + let billing_accounts = vec![foundation_account, staking_pool_account]; + for account in billing_accounts { + if !>::account_exists(&account.clone().into()) { + let _ = Balances::deposit_creating(&account, EXISTENTIAL_DEPOSIT); + } + } +} diff --git a/substrate-node/pallets/pallet-smart-contract/src/types.rs b/substrate-node/pallets/pallet-smart-contract/src/types.rs index 6885292bf..ccd5f070c 100644 --- a/substrate-node/pallets/pallet-smart-contract/src/types.rs +++ b/substrate-node/pallets/pallet-smart-contract/src/types.rs @@ -1,16 +1,23 @@ use crate::{ pallet::{MaxDeploymentDataLength, MaxNodeContractPublicIPs}, - Config, + Call, Config, }; use core::{convert::TryInto, ops::Add}; -use frame_support::{pallet_prelude::ConstU32, BoundedVec, RuntimeDebugNoBound}; +use frame_support::{ + pallet_prelude::ConstU32, + traits::{DefensiveSaturating, IsSubType}, + BoundedVec, RuntimeDebugNoBound, +}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::SaturatedConversion; -use sp_std::prelude::*; +use sp_runtime::{ + traits::{DispatchInfoOf, SignedExtension, Zero}, + transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction}, + SaturatedConversion, +}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; use substrate_fixed::types::U64F64; use tfchain_support::{resources::Resources, types::PublicIP}; - pub type BlockNumber = u64; /// Utility type for managing upgrades/migrations. @@ -27,6 +34,7 @@ pub enum StorageVersion { V9, V10, V11, + V12, } impl Default for StorageVersion { @@ -222,6 +230,17 @@ pub struct ContractLock { pub lock_updated: u64, pub cycles: u16, } +#[derive( + PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, Debug, TypeInfo, MaxEncodedLen, +)] +pub struct ContractPaymentState { + pub standard_reserve: BalanceOf, + pub additional_reserve: BalanceOf, + pub standard_overdraft: BalanceOf, + pub additional_overdraft: BalanceOf, + pub last_updated_seconds: u64, + pub cycles: u16, +} impl + Copy + TryInto> ContractLock { pub fn total_amount_locked(&self) -> BalanceOf { @@ -235,6 +254,123 @@ impl + Copy + TryInto> ContractLock bool { self.extra_amount_locked.saturated_into::() > 0 } + + pub fn is_migrated(&self) -> bool { + self.lock_updated == 0 + } +} + +impl ContractPaymentState +where + BalanceOf: DefensiveSaturating + Copy + Zero + PartialOrd, +{ + // accumulate the standard reserve + pub fn reserve_standard_amount(&mut self, amount: BalanceOf) { + self.standard_reserve.defensive_saturating_accrue(amount); + } + // accumulate the additional reserve + pub fn reserve_additional_amount(&mut self, amount: BalanceOf) { + self.additional_reserve.defensive_saturating_accrue(amount); + } + // accumulate the standard overdraft + pub fn overdraft_standard_amount(&mut self, amount: BalanceOf) { + self.standard_overdraft.defensive_saturating_accrue(amount); + } + // accumulate the additional overdraft + pub fn overdraft_additional_amount(&mut self, amount: BalanceOf) { + self.additional_overdraft + .defensive_saturating_accrue(amount); + } + + // Method to settle the standard overdraft + pub fn settle_overdraft_standard_amount(&mut self) { + self.standard_reserve + .defensive_saturating_accrue(self.standard_overdraft); + self.standard_overdraft = BalanceOf::zero(); + } + + // Method to settle the additional overdraft + pub fn settle_overdraft_additional_amount(&mut self) { + self.additional_reserve + .defensive_saturating_accrue(self.additional_overdraft); + self.additional_overdraft = BalanceOf::zero(); + } + + // Method to settle both standard and additional overdraft + pub fn settle_overdraft(&mut self) { + self.settle_overdraft_standard_amount(); + self.settle_overdraft_additional_amount(); + } + + // Method to return the sum of standard_overdraft and additional_overdraft + pub fn get_overdraft(&self) -> BalanceOf { + self.standard_overdraft + .defensive_saturating_add(self.additional_overdraft) + } + + // Method to return the sum of standard_reserve_amount and additional_reserve_amount + pub fn get_reserve(&self) -> BalanceOf { + self.standard_reserve + .defensive_saturating_add(self.additional_reserve) + } + + // Method to return weather the contract has any reserved balance at all. + pub fn has_reserve(&self) -> bool { + !self.standard_reserve.is_zero() || !self.additional_reserve.is_zero() + } + + // Method to return weather the contract has overdraft or not + pub fn has_overdraft(&self) -> bool { + !self.standard_overdraft.is_zero() || !self.additional_overdraft.is_zero() + } + + // Method to settle partial overdraft + pub fn settle_partial_overdraft(&mut self, amount: BalanceOf) { + let mut remaining_amount = amount; + + // Settle additional overdraft first + if remaining_amount > BalanceOf::zero() { + if remaining_amount >= self.additional_overdraft { + remaining_amount.defensive_saturating_reduce(self.additional_overdraft); + self.additional_reserve + .defensive_saturating_accrue(self.additional_overdraft); + self.additional_overdraft = BalanceOf::zero(); + } else { + self.additional_overdraft + .defensive_saturating_reduce(remaining_amount); + self.additional_reserve + .defensive_saturating_accrue(remaining_amount); + remaining_amount = BalanceOf::zero(); + } + } + + // Settle standard overdraft with any remaining amount + if remaining_amount > BalanceOf::zero() { + if remaining_amount >= self.standard_overdraft { + remaining_amount.defensive_saturating_reduce(self.standard_overdraft); + self.standard_reserve + .defensive_saturating_accrue(self.standard_overdraft); + self.standard_overdraft = BalanceOf::zero(); + } else { + self.standard_overdraft + .defensive_saturating_reduce(remaining_amount); + self.standard_reserve + .defensive_saturating_accrue(remaining_amount); + } + } + } + + pub fn reset_standard_reserve(&mut self) { + self.standard_reserve = BalanceOf::zero(); + } + + pub fn reset_additional_reserve(&mut self) { + self.additional_reserve = BalanceOf::zero(); + } + + pub fn reset_cycles(&mut self) { + self.cycles = 0; + } } #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Default, Debug, TypeInfo)] @@ -286,3 +422,241 @@ pub enum ServiceContractState { AgreementReady, ApprovedByBoth, } + +// This code defines a custom SignedExtension `ContractIdProvides` +// SignedExtension is a trait that allows developers to add custom logic to the transaction validation process. +// It ensures that transactions of type bill_contract_for_block are unique per block based on the provided contract ID. +#[derive(Encode, Decode, Clone, Eq, PartialEq, scale_info::TypeInfo)] +pub struct ContractIdProvides(PhantomData) +where + ::RuntimeCall: IsSubType>; + +impl SignedExtension for ContractIdProvides +where + ::RuntimeCall: IsSubType>, +{ + const IDENTIFIER: &'static str = "ContractIdProvides"; + type AccountId = T::AccountId; + type Call = T::RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed(&self) -> Result<(), TransactionValidityError> { + Ok(()) + } + + // Provides the contract ID in a way that prevents duplicate transactions with the same contract ID. + fn validate( + &self, + _who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + if let Some(local_call) = call.is_sub_type() { + if let Call::bill_contract_for_block { contract_id } = local_call { + return ValidTransaction::with_tag_prefix(Self::IDENTIFIER) + .and_provides(contract_id.to_le_bytes().to_vec()) + .build() + .into(); + } + } + Ok(ValidTransaction::default()) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(|_| ()) + } +} + +impl Debug for ContractIdProvides +where + ::RuntimeCall: IsSubType>, +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "ContractIdProvides") + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl Default for ContractIdProvides +where + ::RuntimeCall: IsSubType>, +{ + fn default() -> Self { + Self(PhantomData) + } +} + +impl ContractIdProvides +where + ::RuntimeCall: IsSubType>, +{ + pub fn new() -> Self { + Self(PhantomData) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Helper function to create a default ContractPaymentState + fn default_contract_payment_state() -> ContractPaymentState { + ContractPaymentState { + last_updated_seconds: 0, + standard_reserve: 0, + additional_reserve: 0, + standard_overdraft: 0, + additional_overdraft: 0, + cycles: 0, + } + } + + #[test] + fn test_settle_overdraft() { + let mut payment_state = default_contract_payment_state(); + payment_state.standard_overdraft = 50; + payment_state.additional_overdraft = 30; + + payment_state.settle_overdraft(); + + assert_eq!(payment_state.standard_overdraft, 0); + assert_eq!(payment_state.additional_overdraft, 0); + } + + #[test] + fn test_reserve_standard_amount() { + let mut payment_state = default_contract_payment_state(); + payment_state.reserve_standard_amount(100); + assert_eq!(payment_state.standard_reserve, 100); + + payment_state.reserve_standard_amount(50); + assert_eq!(payment_state.standard_reserve, 150); + } + + #[test] + fn test_reserve_additional_amount() { + let mut payment_state = default_contract_payment_state(); + payment_state.reserve_additional_amount(200); + assert_eq!(payment_state.additional_reserve, 200); + + payment_state.reserve_additional_amount(100); + assert_eq!(payment_state.additional_reserve, 300); + } + + #[test] + fn test_overdraft_standard_amount() { + let mut payment_state = default_contract_payment_state(); + payment_state.overdraft_standard_amount(150); + assert_eq!(payment_state.standard_overdraft, 150); + + payment_state.overdraft_standard_amount(50); + assert_eq!(payment_state.standard_overdraft, 200); + } + + #[test] + fn test_overdraft_additional_amount() { + let mut payment_state = default_contract_payment_state(); + payment_state.overdraft_additional_amount(75); + assert_eq!(payment_state.additional_overdraft, 75); + + payment_state.overdraft_additional_amount(75); + assert_eq!(payment_state.additional_overdraft, 150); + } + + #[test] + fn test_settle_partial_overdraft() { + let mut payment_state = default_contract_payment_state(); + payment_state.standard_overdraft = 100; + payment_state.additional_overdraft = 50; + + payment_state.settle_partial_overdraft(30); + + // The remaining overdraft should be reduced by 30 + // Assuming 30 is preferably deducted from additional first + assert_eq!(payment_state.standard_overdraft, 100); + assert_eq!(payment_state.additional_overdraft, 20); + + payment_state.settle_partial_overdraft(30); + assert_eq!(payment_state.standard_overdraft, 90); + assert_eq!(payment_state.additional_overdraft, 0); + + payment_state.settle_partial_overdraft(100); + assert_eq!(payment_state.standard_overdraft, 0); + assert_eq!(payment_state.additional_overdraft, 0); + + payment_state.additional_overdraft = 50; + payment_state.settle_partial_overdraft(40); + assert_eq!(payment_state.additional_overdraft, 10); + } + + #[test] + fn test_get_overdraft() { + let mut payment_state = default_contract_payment_state(); + payment_state.standard_overdraft = 200; + payment_state.additional_overdraft = 100; + + let total_overdraft = payment_state.get_overdraft(); + + assert_eq!(total_overdraft, 300); + } + + #[test] + fn test_get_reserve() { + let mut payment_state = default_contract_payment_state(); + payment_state.standard_reserve = 120; + payment_state.additional_reserve = 80; + + let total_reserved = payment_state.get_reserve(); + + assert_eq!(total_reserved, 200); + } + + #[test] + fn test_has_reserve() { + let mut payment_state = default_contract_payment_state(); + assert_eq!(payment_state.has_reserve(), false); + + payment_state.standard_reserve = 120; + payment_state.additional_reserve = 80; + assert_eq!(payment_state.has_reserve(), true); + + let mut payment_state = default_contract_payment_state(); + payment_state.standard_reserve = 120; + assert_eq!(payment_state.has_reserve(), true); + + let mut payment_state = default_contract_payment_state(); + payment_state.additional_reserve = 80; + assert_eq!(payment_state.has_reserve(), true); + } + + #[test] + fn test_has_overdarft() { + let mut payment_state = default_contract_payment_state(); + assert_eq!(payment_state.has_overdraft(), false); + + payment_state.standard_overdraft = 120; + payment_state.additional_overdraft = 80; + assert_eq!(payment_state.has_overdraft(), true); + + let mut payment_state = default_contract_payment_state(); + payment_state.standard_overdraft = 120; + assert_eq!(payment_state.has_overdraft(), true); + + let mut payment_state = default_contract_payment_state(); + payment_state.additional_overdraft = 80; + assert_eq!(payment_state.has_overdraft(), true); + } +} diff --git a/substrate-node/pallets/pallet-smart-contract/src/weights.rs b/substrate-node/pallets/pallet-smart-contract/src/weights.rs index c05881a43..7e44e4f31 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -89,14 +89,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractBillingInformationByID` (r:0 w:1) /// Proof: `SmartContractModule::ContractBillingInformationByID` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SmartContractModule::ContractLock` (r:0 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:0 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) fn create_node_contract() -> Weight { // Proof Size summary in bytes: // Measured: `868` // Estimated: `4333` - // Minimum execution time: 48_412_000 picoseconds. - Weight::from_parts(49_073_000, 4333) + // Minimum execution time: 48_532_000 picoseconds. + Weight::from_parts(49_293_000, 4333) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -110,27 +110,31 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ContractIDByNodeIDAndHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn update_node_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `892` - // Estimated: `4357` - // Minimum execution time: 26_911_000 picoseconds. - Weight::from_parts(27_492_000, 4357) + // Measured: `923` + // Estimated: `4388` + // Minimum execution time: 27_632_000 picoseconds. + Weight::from_parts(28_023_000, 4388) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveNodeContracts` (r:1 w:1) /// Proof: `SmartContractModule::ActiveNodeContracts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) /// Proof: `SmartContractModule::BillingFrequency` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractsToBillAt` (r:1 w:1) @@ -143,11 +147,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ContractIDByNodeIDAndHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `1203` - // Estimated: `4668` - // Minimum execution time: 60_164_000 picoseconds. - Weight::from_parts(61_396_000, 4668) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1650` + // Estimated: `7590` + // Minimum execution time: 75_803_000 picoseconds. + Weight::from_parts(78_449_000, 7590) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -164,14 +168,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `SmartContractModule::Contracts` (r:0 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SmartContractModule::ContractLock` (r:0 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:0 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) fn create_name_contract() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3805` - // Minimum execution time: 24_697_000 picoseconds. - Weight::from_parts(25_468_000, 3805) + // Minimum execution time: 24_757_000 picoseconds. + Weight::from_parts(25_237_000, 3805) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -179,14 +183,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Twins` (r:1 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) /// Proof: `SmartContractModule::BillingFrequency` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractsToBillAt` (r:1 w:1) @@ -195,10 +199,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ContractIDByNameRegistration` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_name_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `919` - // Estimated: `4384` - // Minimum execution time: 46_268_000 picoseconds. - Weight::from_parts(47_641_000, 4384) + // Measured: `949` + // Estimated: `4414` + // Minimum execution time: 51_417_000 picoseconds. + Weight::from_parts(52_810_000, 4414) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -218,10 +222,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ContractBillingInformationByID` (`max_values`: None, `max_size`: None, mode: `Measured`) fn add_nru_reports() -> Weight { // Proof Size summary in bytes: - // Measured: `1292` - // Estimated: `4757` - // Minimum execution time: 38_112_000 picoseconds. - Weight::from_parts(38_763_000, 4757) + // Measured: `1286` + // Estimated: `4751` + // Minimum execution time: 37_891_000 picoseconds. + Weight::from_parts(38_723_000, 4751) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -235,10 +239,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::NodeContractResources` (`max_values`: None, `max_size`: None, mode: `Measured`) fn report_contract_resources() -> Weight { // Proof Size summary in bytes: - // Measured: `771` - // Estimated: `4236` - // Minimum execution time: 23_053_000 picoseconds. - Weight::from_parts(23_394_000, 4236) + // Measured: `765` + // Estimated: `4230` + // Minimum execution time: 22_993_000 picoseconds. + Weight::from_parts(23_644_000, 4230) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -262,35 +266,37 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `SmartContractModule::Contracts` (r:0 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SmartContractModule::ContractLock` (r:0 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:0 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) fn create_rent_contract() -> Weight { // Proof Size summary in bytes: // Measured: `776` // Estimated: `4241` - // Minimum execution time: 34_856_000 picoseconds. - Weight::from_parts(35_767_000, 4241) + // Minimum execution time: 34_595_000 picoseconds. + Weight::from_parts(35_197_000, 4241) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`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::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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::NodePower` (r:1 w:0) - /// Proof: `TfgridModule::NodePower` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::DedicatedNodesExtraFee` (r:1 w:0) /// Proof: `SmartContractModule::DedicatedNodesExtraFee` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -301,11 +307,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_rent_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `1284` - // Estimated: `4749` - // Minimum execution time: 59_392_000 picoseconds. - Weight::from_parts(60_414_000, 4749) - .saturating_add(T::DbWeight::get().reads(12_u64)) + // Measured: `1607` + // Estimated: `7547` + // Minimum execution time: 72_758_000 picoseconds. + Weight::from_parts(73_970_000, 7547) + .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `SmartContractModule::SolutionProviderID` (r:1 w:1) @@ -316,8 +322,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 9_949_000 picoseconds. - Weight::from_parts(10_199_000, 1522) + // Minimum execution time: 9_668_000 picoseconds. + Weight::from_parts(9_969_000, 1522) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -327,29 +333,31 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `215` // Estimated: `3680` - // Minimum execution time: 12_814_000 picoseconds. - Weight::from_parts(13_205_000, 3680) + // Minimum execution time: 12_674_000 picoseconds. + Weight::from_parts(12_944_000, 3680) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:0) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`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: `TfgridModule::Nodes` (r:1 w:0) - /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::NodeContractResources` (r:1 w:0) /// Proof: `SmartContractModule::NodeContractResources` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveRentContractForNode` (r:1 w:0) @@ -360,18 +368,16 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TFTPriceModule::MinTftPrice` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `TFTPriceModule::MaxTftPrice` (r:1 w:0) /// Proof: `TFTPriceModule::MaxTftPrice` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn bill_contract_for_block() -> Weight { // Proof Size summary in bytes: - // Measured: `1608` - // Estimated: `5073` - // Minimum execution time: 79_811_000 picoseconds. - Weight::from_parts(81_795_000, 5073) - .saturating_add(T::DbWeight::get().reads(16_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Measured: `2077` + // Estimated: `8017` + // Minimum execution time: 86_263_000 picoseconds. + Weight::from_parts(87_505_000, 8017) + .saturating_add(T::DbWeight::get().reads(17_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:2 w:0) /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -383,8 +389,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `395` // Estimated: `6335` - // Minimum execution time: 18_665_000 picoseconds. - Weight::from_parts(19_127_000, 6335) + // Minimum execution time: 18_384_000 picoseconds. + Weight::from_parts(18_725_000, 6335) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -396,8 +402,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 16_552_000 picoseconds. - Weight::from_parts(17_192_000, 3954) + // Minimum execution time: 16_732_000 picoseconds. + Weight::from_parts(17_162_000, 3954) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -409,8 +415,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 16_260_000 picoseconds. - Weight::from_parts(16_801_000, 3954) + // Minimum execution time: 16_351_000 picoseconds. + Weight::from_parts(16_632_000, 3954) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -422,8 +428,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_512_000 picoseconds. - Weight::from_parts(17_032_000, 3967) + // Minimum execution time: 16_271_000 picoseconds. + Weight::from_parts(16_781_000, 3967) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -435,8 +441,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 17_183_000 picoseconds. - Weight::from_parts(17_914_000, 3967) + // Minimum execution time: 17_022_000 picoseconds. + Weight::from_parts(17_413_000, 3967) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -448,8 +454,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_181_000 picoseconds. - Weight::from_parts(16_832_000, 3967) + // Minimum execution time: 15_990_000 picoseconds. + Weight::from_parts(16_321_000, 3967) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -467,8 +473,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `841` // Estimated: `6781` - // Minimum execution time: 29_806_000 picoseconds. - Weight::from_parts(30_869_000, 6781) + // Minimum execution time: 28_924_000 picoseconds. + Weight::from_parts(29_586_000, 6781) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -478,7 +484,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 7_434_000 picoseconds. + // Minimum execution time: 7_474_000 picoseconds. Weight::from_parts(7_725_000, 1522) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -491,10 +497,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) fn attach_solution_provider_id() -> Weight { // Proof Size summary in bytes: - // Measured: `971` - // Estimated: `4436` - // Minimum execution time: 21_731_000 picoseconds. - Weight::from_parts(22_693_000, 4436) + // Measured: `965` + // Estimated: `4430` + // Minimum execution time: 21_971_000 picoseconds. + Weight::from_parts(22_552_000, 4430) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -514,8 +520,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `733` // Estimated: `4198` - // Minimum execution time: 23_585_000 picoseconds. - Weight::from_parts(23_975_000, 4198) + // Minimum execution time: 23_114_000 picoseconds. + Weight::from_parts(23_544_000, 4198) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -523,16 +529,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveNodeContracts` (r:1 w:1) /// Proof: `SmartContractModule::ActiveNodeContracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) /// Proof: `SmartContractModule::BillingFrequency` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractsToBillAt` (r:1 w:1) @@ -545,11 +555,11 @@ impl WeightInfo for SubstrateWeight { /// Proof: `SmartContractModule::ContractIDByNodeIDAndHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_contract_collective() -> Weight { // Proof Size summary in bytes: - // Measured: `1203` - // Estimated: `4668` - // Minimum execution time: 58_099_000 picoseconds. - Weight::from_parts(59_022_000, 4668) - .saturating_add(T::DbWeight::get().reads(9_u64)) + // Measured: `1650` + // Estimated: `7590` + // Minimum execution time: 74_791_000 picoseconds. + Weight::from_parts(76_285_000, 7590) + .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } } @@ -584,14 +594,14 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractBillingInformationByID` (r:0 w:1) /// Proof: `SmartContractModule::ContractBillingInformationByID` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SmartContractModule::ContractLock` (r:0 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:0 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) fn create_node_contract() -> Weight { // Proof Size summary in bytes: // Measured: `868` // Estimated: `4333` - // Minimum execution time: 48_412_000 picoseconds. - Weight::from_parts(49_073_000, 4333) + // Minimum execution time: 48_532_000 picoseconds. + Weight::from_parts(49_293_000, 4333) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -605,27 +615,31 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ContractIDByNodeIDAndHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn update_node_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `892` - // Estimated: `4357` - // Minimum execution time: 26_911_000 picoseconds. - Weight::from_parts(27_492_000, 4357) + // Measured: `923` + // Estimated: `4388` + // Minimum execution time: 27_632_000 picoseconds. + Weight::from_parts(28_023_000, 4388) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveNodeContracts` (r:1 w:1) /// Proof: `SmartContractModule::ActiveNodeContracts` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) /// Proof: `SmartContractModule::BillingFrequency` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractsToBillAt` (r:1 w:1) @@ -638,11 +652,11 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ContractIDByNodeIDAndHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `1203` - // Estimated: `4668` - // Minimum execution time: 60_164_000 picoseconds. - Weight::from_parts(61_396_000, 4668) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1650` + // Estimated: `7590` + // Minimum execution time: 75_803_000 picoseconds. + Weight::from_parts(78_449_000, 7590) + .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -659,14 +673,14 @@ impl WeightInfo for () { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `SmartContractModule::Contracts` (r:0 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SmartContractModule::ContractLock` (r:0 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:0 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) fn create_name_contract() -> Weight { // Proof Size summary in bytes: // Measured: `340` // Estimated: `3805` - // Minimum execution time: 24_697_000 picoseconds. - Weight::from_parts(25_468_000, 3805) + // Minimum execution time: 24_757_000 picoseconds. + Weight::from_parts(25_237_000, 3805) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -674,14 +688,14 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::Twins` (r:1 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) /// Proof: `SmartContractModule::BillingFrequency` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractsToBillAt` (r:1 w:1) @@ -690,10 +704,10 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ContractIDByNameRegistration` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_name_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `919` - // Estimated: `4384` - // Minimum execution time: 46_268_000 picoseconds. - Weight::from_parts(47_641_000, 4384) + // Measured: `949` + // Estimated: `4414` + // Minimum execution time: 51_417_000 picoseconds. + Weight::from_parts(52_810_000, 4414) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -713,10 +727,10 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ContractBillingInformationByID` (`max_values`: None, `max_size`: None, mode: `Measured`) fn add_nru_reports() -> Weight { // Proof Size summary in bytes: - // Measured: `1292` - // Estimated: `4757` - // Minimum execution time: 38_112_000 picoseconds. - Weight::from_parts(38_763_000, 4757) + // Measured: `1286` + // Estimated: `4751` + // Minimum execution time: 37_891_000 picoseconds. + Weight::from_parts(38_723_000, 4751) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -730,10 +744,10 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::NodeContractResources` (`max_values`: None, `max_size`: None, mode: `Measured`) fn report_contract_resources() -> Weight { // Proof Size summary in bytes: - // Measured: `771` - // Estimated: `4236` - // Minimum execution time: 23_053_000 picoseconds. - Weight::from_parts(23_394_000, 4236) + // Measured: `765` + // Estimated: `4230` + // Minimum execution time: 22_993_000 picoseconds. + Weight::from_parts(23_644_000, 4230) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -757,35 +771,37 @@ impl WeightInfo for () { /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) /// Storage: `SmartContractModule::Contracts` (r:0 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `SmartContractModule::ContractLock` (r:0 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `SmartContractModule::ContractPaymentState` (r:0 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) fn create_rent_contract() -> Weight { // Proof Size summary in bytes: // Measured: `776` // Estimated: `4241` - // Minimum execution time: 34_856_000 picoseconds. - Weight::from_parts(35_767_000, 4241) + // Minimum execution time: 34_595_000 picoseconds. + Weight::from_parts(35_197_000, 4241) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:1) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`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::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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::NodePower` (r:1 w:0) - /// Proof: `TfgridModule::NodePower` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::DedicatedNodesExtraFee` (r:1 w:0) /// Proof: `SmartContractModule::DedicatedNodesExtraFee` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) @@ -796,11 +812,11 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ActiveRentContractForNode` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_rent_contract() -> Weight { // Proof Size summary in bytes: - // Measured: `1284` - // Estimated: `4749` - // Minimum execution time: 59_392_000 picoseconds. - Weight::from_parts(60_414_000, 4749) - .saturating_add(RocksDbWeight::get().reads(12_u64)) + // Measured: `1607` + // Estimated: `7547` + // Minimum execution time: 72_758_000 picoseconds. + Weight::from_parts(73_970_000, 7547) + .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `SmartContractModule::SolutionProviderID` (r:1 w:1) @@ -811,8 +827,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 9_949_000 picoseconds. - Weight::from_parts(10_199_000, 1522) + // Minimum execution time: 9_668_000 picoseconds. + Weight::from_parts(9_969_000, 1522) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -822,29 +838,31 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `215` // Estimated: `3680` - // Minimum execution time: 12_814_000 picoseconds. - Weight::from_parts(13_205_000, 3680) + // Minimum execution time: 12_674_000 picoseconds. + Weight::from_parts(12_944_000, 3680) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `SmartContractModule::Contracts` (r:1 w:0) /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`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: `TfgridModule::Nodes` (r:1 w:0) - /// Proof: `TfgridModule::Nodes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::NodeContractResources` (r:1 w:0) /// Proof: `SmartContractModule::NodeContractResources` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveRentContractForNode` (r:1 w:0) @@ -855,18 +873,16 @@ impl WeightInfo for () { /// Proof: `TFTPriceModule::MinTftPrice` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `TFTPriceModule::MaxTftPrice` (r:1 w:0) /// Proof: `TFTPriceModule::MaxTftPrice` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn bill_contract_for_block() -> Weight { // Proof Size summary in bytes: - // Measured: `1608` - // Estimated: `5073` - // Minimum execution time: 79_811_000 picoseconds. - Weight::from_parts(81_795_000, 5073) - .saturating_add(RocksDbWeight::get().reads(16_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Measured: `2077` + // Estimated: `8017` + // Minimum execution time: 86_263_000 picoseconds. + Weight::from_parts(87_505_000, 8017) + .saturating_add(RocksDbWeight::get().reads(17_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:2 w:0) /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -878,8 +894,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `395` // Estimated: `6335` - // Minimum execution time: 18_665_000 picoseconds. - Weight::from_parts(19_127_000, 6335) + // Minimum execution time: 18_384_000 picoseconds. + Weight::from_parts(18_725_000, 6335) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -891,8 +907,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 16_552_000 picoseconds. - Weight::from_parts(17_192_000, 3954) + // Minimum execution time: 16_732_000 picoseconds. + Weight::from_parts(17_162_000, 3954) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -904,8 +920,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `489` // Estimated: `3954` - // Minimum execution time: 16_260_000 picoseconds. - Weight::from_parts(16_801_000, 3954) + // Minimum execution time: 16_351_000 picoseconds. + Weight::from_parts(16_632_000, 3954) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -917,8 +933,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_512_000 picoseconds. - Weight::from_parts(17_032_000, 3967) + // Minimum execution time: 16_271_000 picoseconds. + Weight::from_parts(16_781_000, 3967) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -930,8 +946,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 17_183_000 picoseconds. - Weight::from_parts(17_914_000, 3967) + // Minimum execution time: 17_022_000 picoseconds. + Weight::from_parts(17_413_000, 3967) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -943,8 +959,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `502` // Estimated: `3967` - // Minimum execution time: 16_181_000 picoseconds. - Weight::from_parts(16_832_000, 3967) + // Minimum execution time: 15_990_000 picoseconds. + Weight::from_parts(16_321_000, 3967) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -962,8 +978,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `841` // Estimated: `6781` - // Minimum execution time: 29_806_000 picoseconds. - Weight::from_parts(30_869_000, 6781) + // Minimum execution time: 28_924_000 picoseconds. + Weight::from_parts(29_586_000, 6781) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -973,7 +989,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `37` // Estimated: `1522` - // Minimum execution time: 7_434_000 picoseconds. + // Minimum execution time: 7_474_000 picoseconds. Weight::from_parts(7_725_000, 1522) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -986,10 +1002,10 @@ impl WeightInfo for () { /// Proof: `TfgridModule::TwinIdByAccountID` (`max_values`: None, `max_size`: None, mode: `Measured`) fn attach_solution_provider_id() -> Weight { // Proof Size summary in bytes: - // Measured: `971` - // Estimated: `4436` - // Minimum execution time: 21_731_000 picoseconds. - Weight::from_parts(22_693_000, 4436) + // Measured: `965` + // Estimated: `4430` + // Minimum execution time: 21_971_000 picoseconds. + Weight::from_parts(22_552_000, 4430) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1009,8 +1025,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `733` // Estimated: `4198` - // Minimum execution time: 23_585_000 picoseconds. - Weight::from_parts(23_975_000, 4198) + // Minimum execution time: 23_114_000 picoseconds. + Weight::from_parts(23_544_000, 4198) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1018,16 +1034,20 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::Contracts` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ActiveNodeContracts` (r:1 w:1) /// Proof: `SmartContractModule::ActiveNodeContracts` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::Twins` (r:1 w:0) + /// Storage: `TfgridModule::Twins` (r:2 w:0) /// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) + /// Proof: `TfgridModule::PricingPolicies` (`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: `SmartContractModule::ContractPaymentState` (r:1 w:1) + /// Proof: `SmartContractModule::ContractPaymentState` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `TfgridModule::TwinBoundedAccountID` (r:1 w:0) /// 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: `SmartContractModule::ContractLock` (r:1 w:1) - /// Proof: `SmartContractModule::ContractLock` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `TfgridModule::PricingPolicies` (r:1 w:0) - /// Proof: `TfgridModule::PricingPolicies` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::BillingFrequency` (r:1 w:0) /// Proof: `SmartContractModule::BillingFrequency` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `SmartContractModule::ContractsToBillAt` (r:1 w:1) @@ -1040,11 +1060,11 @@ impl WeightInfo for () { /// Proof: `SmartContractModule::ContractIDByNodeIDAndHash` (`max_values`: None, `max_size`: None, mode: `Measured`) fn cancel_contract_collective() -> Weight { // Proof Size summary in bytes: - // Measured: `1203` - // Estimated: `4668` - // Minimum execution time: 58_099_000 picoseconds. - Weight::from_parts(59_022_000, 4668) - .saturating_add(RocksDbWeight::get().reads(9_u64)) + // Measured: `1650` + // Estimated: `7590` + // Minimum execution time: 74_791_000 picoseconds. + Weight::from_parts(76_285_000, 7590) + .saturating_add(RocksDbWeight::get().reads(12_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 075014e40..18ce069d6 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: @@ -76,8 +76,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_485_000 picoseconds. - Weight::from_parts(2_575_000, 0) + // Minimum execution time: 2_515_000 picoseconds. + Weight::from_parts(2_655_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -94,8 +94,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3961` - // Minimum execution time: 20_870_000 picoseconds. - Weight::from_parts(21_480_000, 3961) + // Minimum execution time: 20_518_000 picoseconds. + Weight::from_parts(20_980_000, 3961) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -109,8 +109,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `507` // Estimated: `3972` - // Minimum execution time: 22_793_000 picoseconds. - Weight::from_parts(23_074_000, 3972) + // Minimum execution time: 22_262_000 picoseconds. + Weight::from_parts(22_653_000, 3972) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -124,8 +124,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3918` - // Minimum execution time: 16_180_000 picoseconds. - Weight::from_parts(16_651_000, 3918) + // Minimum execution time: 16_531_000 picoseconds. + Weight::from_parts(17_012_000, 3918) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -135,8 +135,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_675_000 picoseconds. - Weight::from_parts(14_097_000, 3877) + // Minimum execution time: 13_476_000 picoseconds. + Weight::from_parts(13_826_000, 3877) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -148,8 +148,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 18_404_000 picoseconds. - Weight::from_parts(18_815_000, 4034) + // Minimum execution time: 18_355_000 picoseconds. + Weight::from_parts(18_695_000, 4034) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -161,8 +161,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 17_413_000 picoseconds. - Weight::from_parts(17_874_000, 4034) + // Minimum execution time: 17_534_000 picoseconds. + Weight::from_parts(17_904_000, 4034) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -190,8 +190,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `905` // Estimated: `11795` - // Minimum execution time: 49_384_000 picoseconds. - Weight::from_parts(50_565_000, 11795) + // Minimum execution time: 48_913_000 picoseconds. + Weight::from_parts(49_483_000, 11795) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -207,8 +207,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `661` // Estimated: `4126` - // Minimum execution time: 28_183_000 picoseconds. - Weight::from_parts(28_875_000, 4126) + // Minimum execution time: 27_392_000 picoseconds. + Weight::from_parts(28_073_000, 4126) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -222,8 +222,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `956` // Estimated: `11846` - // Minimum execution time: 35_847_000 picoseconds. - Weight::from_parts(36_519_000, 11846) + // Minimum execution time: 35_166_000 picoseconds. + Weight::from_parts(35_728_000, 11846) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -239,8 +239,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 19_406_000 picoseconds. - Weight::from_parts(19_827_000, 3919) + // Minimum execution time: 18_906_000 picoseconds. + Weight::from_parts(19_326_000, 3919) .saturating_add(T::DbWeight::get().reads(4_u64)) } /// Storage: `TfgridModule::Farms` (r:1 w:0) @@ -253,8 +253,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `779` // Estimated: `4244` - // Minimum execution time: 25_348_000 picoseconds. - Weight::from_parts(25_999_000, 4244) + // Minimum execution time: 25_027_000 picoseconds. + Weight::from_parts(25_488_000, 4244) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -274,8 +274,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `682` // Estimated: `4147` - // Minimum execution time: 28_755_000 picoseconds. - Weight::from_parts(29_315_000, 4147) + // Minimum execution time: 28_053_000 picoseconds. + Weight::from_parts(28_715_000, 4147) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -291,7 +291,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `235` // Estimated: `3700` - // Minimum execution time: 14_818_000 picoseconds. + // Minimum execution time: 14_828_000 picoseconds. Weight::from_parts(15_129_000, 3700) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) @@ -304,8 +304,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `428` // Estimated: `3893` - // Minimum execution time: 15_419_000 picoseconds. - Weight::from_parts(15_700_000, 3893) + // Minimum execution time: 15_199_000 picoseconds. + Weight::from_parts(15_610_000, 3893) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -319,8 +319,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `3599` - // Minimum execution time: 12_674_000 picoseconds. - Weight::from_parts(12_985_000, 3599) + // Minimum execution time: 12_534_000 picoseconds. + Weight::from_parts(12_795_000, 3599) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -334,8 +334,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `382` // Estimated: `3847` - // Minimum execution time: 17_112_000 picoseconds. - Weight::from_parts(17_523_000, 3847) + // Minimum execution time: 16_962_000 picoseconds. + Weight::from_parts(17_433_000, 3847) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -347,7 +347,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 10_249_000 picoseconds. + // Minimum execution time: 10_480_000 picoseconds. Weight::from_parts(10_730_000, 1619) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -360,8 +360,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3605` - // Minimum execution time: 7_555_000 picoseconds. - Weight::from_parts(7_835_000, 3605) + // Minimum execution time: 7_444_000 picoseconds. + Weight::from_parts(7_664_000, 3605) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -385,8 +385,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `828` // Estimated: `4293` - // Minimum execution time: 33_413_000 picoseconds. - Weight::from_parts(34_295_000, 4293) + // Minimum execution time: 33_273_000 picoseconds. + Weight::from_parts(33_854_000, 4293) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -396,8 +396,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_816_000 picoseconds. - Weight::from_parts(14_097_000, 3877) + // Minimum execution time: 13_676_000 picoseconds. + Weight::from_parts(14_137_000, 3877) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -407,8 +407,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_856_000 picoseconds. - Weight::from_parts(14_497_000, 3877) + // Minimum execution time: 14_136_000 picoseconds. + Weight::from_parts(14_387_000, 3877) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -418,8 +418,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_711_000 picoseconds. - Weight::from_parts(5_882_000, 0) + // Minimum execution time: 5_651_000 picoseconds. + Weight::from_parts(5_821_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::AllowedNodeCertifiers` (r:1 w:1) @@ -428,8 +428,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `355` // Estimated: `1840` - // Minimum execution time: 10_059_000 picoseconds. - Weight::from_parts(10_360_000, 1840) + // Minimum execution time: 9_799_000 picoseconds. + Weight::from_parts(10_109_000, 1840) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -439,8 +439,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `413` // Estimated: `1898` - // Minimum execution time: 12_263_000 picoseconds. - Weight::from_parts(12_624_000, 1898) + // Minimum execution time: 12_233_000 picoseconds. + Weight::from_parts(12_504_000, 1898) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -450,8 +450,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `294` // Estimated: `3759` - // Minimum execution time: 13_365_000 picoseconds. - Weight::from_parts(13_646_000, 3759) + // Minimum execution time: 13_325_000 picoseconds. + Weight::from_parts(13_706_000, 3759) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -465,8 +465,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `572` // Estimated: `4037` - // Minimum execution time: 22_322_000 picoseconds. - Weight::from_parts(23_254_000, 4037) + // Minimum execution time: 22_302_000 picoseconds. + Weight::from_parts(22_943_000, 4037) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -476,8 +476,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 8_176_000 picoseconds. - Weight::from_parts(8_366_000, 1619) + // Minimum execution time: 8_096_000 picoseconds. + Weight::from_parts(8_275_000, 1619) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -493,8 +493,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `621` // Estimated: `4086` - // Minimum execution time: 23_354_000 picoseconds. - Weight::from_parts(23_725_000, 4086) + // Minimum execution time: 35_657_000 picoseconds. + Weight::from_parts(38_282_000, 4086) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -514,8 +514,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `792` // Estimated: `4257` - // Minimum execution time: 26_710_000 picoseconds. - Weight::from_parts(27_522_000, 4257) + // Minimum execution time: 26_661_000 picoseconds. + Weight::from_parts(27_592_000, 4257) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -527,8 +527,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3852` - // Minimum execution time: 12_113_000 picoseconds. - Weight::from_parts(12_413_000, 3852) + // Minimum execution time: 11_993_000 picoseconds. + Weight::from_parts(12_353_000, 3852) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -544,8 +544,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 18_565_000 picoseconds. - Weight::from_parts(19_086_000, 3919) + // Minimum execution time: 18_374_000 picoseconds. + Weight::from_parts(18_755_000, 3919) .saturating_add(T::DbWeight::get().reads(4_u64)) } } @@ -558,8 +558,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_485_000 picoseconds. - Weight::from_parts(2_575_000, 0) + // Minimum execution time: 2_515_000 picoseconds. + Weight::from_parts(2_655_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::TwinIdByAccountID` (r:1 w:0) @@ -576,8 +576,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `496` // Estimated: `3961` - // Minimum execution time: 20_870_000 picoseconds. - Weight::from_parts(21_480_000, 3961) + // Minimum execution time: 20_518_000 picoseconds. + Weight::from_parts(20_980_000, 3961) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -591,8 +591,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `507` // Estimated: `3972` - // Minimum execution time: 22_793_000 picoseconds. - Weight::from_parts(23_074_000, 3972) + // Minimum execution time: 22_262_000 picoseconds. + Weight::from_parts(22_653_000, 3972) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -606,8 +606,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `453` // Estimated: `3918` - // Minimum execution time: 16_180_000 picoseconds. - Weight::from_parts(16_651_000, 3918) + // Minimum execution time: 16_531_000 picoseconds. + Weight::from_parts(17_012_000, 3918) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -617,8 +617,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_675_000 picoseconds. - Weight::from_parts(14_097_000, 3877) + // Minimum execution time: 13_476_000 picoseconds. + Weight::from_parts(13_826_000, 3877) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -630,8 +630,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 18_404_000 picoseconds. - Weight::from_parts(18_815_000, 4034) + // Minimum execution time: 18_355_000 picoseconds. + Weight::from_parts(18_695_000, 4034) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -643,8 +643,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `569` // Estimated: `4034` - // Minimum execution time: 17_413_000 picoseconds. - Weight::from_parts(17_874_000, 4034) + // Minimum execution time: 17_534_000 picoseconds. + Weight::from_parts(17_904_000, 4034) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -672,8 +672,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `905` // Estimated: `11795` - // Minimum execution time: 49_384_000 picoseconds. - Weight::from_parts(50_565_000, 11795) + // Minimum execution time: 48_913_000 picoseconds. + Weight::from_parts(49_483_000, 11795) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -689,8 +689,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `661` // Estimated: `4126` - // Minimum execution time: 28_183_000 picoseconds. - Weight::from_parts(28_875_000, 4126) + // Minimum execution time: 27_392_000 picoseconds. + Weight::from_parts(28_073_000, 4126) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -704,8 +704,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `956` // Estimated: `11846` - // Minimum execution time: 35_847_000 picoseconds. - Weight::from_parts(36_519_000, 11846) + // Minimum execution time: 35_166_000 picoseconds. + Weight::from_parts(35_728_000, 11846) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -721,8 +721,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 19_406_000 picoseconds. - Weight::from_parts(19_827_000, 3919) + // Minimum execution time: 18_906_000 picoseconds. + Weight::from_parts(19_326_000, 3919) .saturating_add(RocksDbWeight::get().reads(4_u64)) } /// Storage: `TfgridModule::Farms` (r:1 w:0) @@ -735,8 +735,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `779` // Estimated: `4244` - // Minimum execution time: 25_348_000 picoseconds. - Weight::from_parts(25_999_000, 4244) + // Minimum execution time: 25_027_000 picoseconds. + Weight::from_parts(25_488_000, 4244) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -756,8 +756,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `682` // Estimated: `4147` - // Minimum execution time: 28_755_000 picoseconds. - Weight::from_parts(29_315_000, 4147) + // Minimum execution time: 28_053_000 picoseconds. + Weight::from_parts(28_715_000, 4147) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -773,7 +773,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `235` // Estimated: `3700` - // Minimum execution time: 14_818_000 picoseconds. + // Minimum execution time: 14_828_000 picoseconds. Weight::from_parts(15_129_000, 3700) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) @@ -786,8 +786,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `428` // Estimated: `3893` - // Minimum execution time: 15_419_000 picoseconds. - Weight::from_parts(15_700_000, 3893) + // Minimum execution time: 15_199_000 picoseconds. + Weight::from_parts(15_610_000, 3893) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -801,8 +801,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `3599` - // Minimum execution time: 12_674_000 picoseconds. - Weight::from_parts(12_985_000, 3599) + // Minimum execution time: 12_534_000 picoseconds. + Weight::from_parts(12_795_000, 3599) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -816,8 +816,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `382` // Estimated: `3847` - // Minimum execution time: 17_112_000 picoseconds. - Weight::from_parts(17_523_000, 3847) + // Minimum execution time: 16_962_000 picoseconds. + Weight::from_parts(17_433_000, 3847) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -829,7 +829,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 10_249_000 picoseconds. + // Minimum execution time: 10_480_000 picoseconds. Weight::from_parts(10_730_000, 1619) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -842,8 +842,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `140` // Estimated: `3605` - // Minimum execution time: 7_555_000 picoseconds. - Weight::from_parts(7_835_000, 3605) + // Minimum execution time: 7_444_000 picoseconds. + Weight::from_parts(7_664_000, 3605) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -867,8 +867,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `828` // Estimated: `4293` - // Minimum execution time: 33_413_000 picoseconds. - Weight::from_parts(34_295_000, 4293) + // Minimum execution time: 33_273_000 picoseconds. + Weight::from_parts(33_854_000, 4293) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -878,8 +878,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_816_000 picoseconds. - Weight::from_parts(14_097_000, 3877) + // Minimum execution time: 13_676_000 picoseconds. + Weight::from_parts(14_137_000, 3877) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -889,8 +889,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `412` // Estimated: `3877` - // Minimum execution time: 13_856_000 picoseconds. - Weight::from_parts(14_497_000, 3877) + // Minimum execution time: 14_136_000 picoseconds. + Weight::from_parts(14_387_000, 3877) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -900,8 +900,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_711_000 picoseconds. - Weight::from_parts(5_882_000, 0) + // Minimum execution time: 5_651_000 picoseconds. + Weight::from_parts(5_821_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `TfgridModule::AllowedNodeCertifiers` (r:1 w:1) @@ -910,8 +910,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `355` // Estimated: `1840` - // Minimum execution time: 10_059_000 picoseconds. - Weight::from_parts(10_360_000, 1840) + // Minimum execution time: 9_799_000 picoseconds. + Weight::from_parts(10_109_000, 1840) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -921,8 +921,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `413` // Estimated: `1898` - // Minimum execution time: 12_263_000 picoseconds. - Weight::from_parts(12_624_000, 1898) + // Minimum execution time: 12_233_000 picoseconds. + Weight::from_parts(12_504_000, 1898) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -932,8 +932,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `294` // Estimated: `3759` - // Minimum execution time: 13_365_000 picoseconds. - Weight::from_parts(13_646_000, 3759) + // Minimum execution time: 13_325_000 picoseconds. + Weight::from_parts(13_706_000, 3759) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -947,8 +947,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `572` // Estimated: `4037` - // Minimum execution time: 22_322_000 picoseconds. - Weight::from_parts(23_254_000, 4037) + // Minimum execution time: 22_302_000 picoseconds. + Weight::from_parts(22_943_000, 4037) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -958,8 +958,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `134` // Estimated: `1619` - // Minimum execution time: 8_176_000 picoseconds. - Weight::from_parts(8_366_000, 1619) + // Minimum execution time: 8_096_000 picoseconds. + Weight::from_parts(8_275_000, 1619) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -975,8 +975,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `621` // Estimated: `4086` - // Minimum execution time: 23_354_000 picoseconds. - Weight::from_parts(23_725_000, 4086) + // Minimum execution time: 35_657_000 picoseconds. + Weight::from_parts(38_282_000, 4086) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -996,8 +996,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `792` // Estimated: `4257` - // Minimum execution time: 26_710_000 picoseconds. - Weight::from_parts(27_522_000, 4257) + // Minimum execution time: 26_661_000 picoseconds. + Weight::from_parts(27_592_000, 4257) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1009,8 +1009,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3852` - // Minimum execution time: 12_113_000 picoseconds. - Weight::from_parts(12_413_000, 3852) + // Minimum execution time: 11_993_000 picoseconds. + Weight::from_parts(12_353_000, 3852) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1026,8 +1026,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `454` // Estimated: `3919` - // Minimum execution time: 18_565_000 picoseconds. - Weight::from_parts(19_086_000, 3919) + // Minimum execution time: 18_374_000 picoseconds. + Weight::from_parts(18_755_000, 3919) .saturating_add(RocksDbWeight::get().reads(4_u64)) } } diff --git a/substrate-node/pallets/pallet-tft-bridge/src/weights.rs b/substrate-node/pallets/pallet-tft-bridge/src/weights.rs index 0c69c8cdd..8763e9d61 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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: 7_184_000 picoseconds. - Weight::from_parts(7_525_000, 1741) + // Minimum execution time: 7_174_000 picoseconds. + Weight::from_parts(7_444_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: 7_153_000 picoseconds. - Weight::from_parts(7_394_000, 1774) + // Minimum execution time: 7_053_000 picoseconds. + Weight::from_parts(7_314_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_235_000 picoseconds. - Weight::from_parts(2_385_000, 0) + // Minimum execution time: 2_234_000 picoseconds. + Weight::from_parts(2_374_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_295_000, 0) + // Minimum execution time: 2_224_000 picoseconds. + Weight::from_parts(2_335_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_284_000 picoseconds. - Weight::from_parts(2_344_000, 0) + // Minimum execution time: 2_184_000 picoseconds. + Weight::from_parts(2_305_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: 43_822_000 picoseconds. - Weight::from_parts(44_784_000, 3593) + // Minimum execution time: 43_151_000 picoseconds. + Weight::from_parts(43_813_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_426_000 picoseconds. - Weight::from_parts(62_288_000, 3964) + // Minimum execution time: 59_853_000 picoseconds. + Weight::from_parts(60_825_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: 26_129_000 picoseconds. - Weight::from_parts(26_690_000, 4096) + // Minimum execution time: 25_599_000 picoseconds. + Weight::from_parts(26_581_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: 18_625_000 picoseconds. - Weight::from_parts(19_167_000, 4036) + // Minimum execution time: 18_165_000 picoseconds. + Weight::from_parts(18_625_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: 21_801_000 picoseconds. - Weight::from_parts(22_292_000, 3850) + // Minimum execution time: 21_491_000 picoseconds. + Weight::from_parts(22_082_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: 18_846_000 picoseconds. - Weight::from_parts(19_317_000, 4025) + // Minimum execution time: 18_675_000 picoseconds. + Weight::from_parts(19_096_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: 7_184_000 picoseconds. - Weight::from_parts(7_525_000, 1741) + // Minimum execution time: 7_174_000 picoseconds. + Weight::from_parts(7_444_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: 7_153_000 picoseconds. - Weight::from_parts(7_394_000, 1774) + // Minimum execution time: 7_053_000 picoseconds. + Weight::from_parts(7_314_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_235_000 picoseconds. - Weight::from_parts(2_385_000, 0) + // Minimum execution time: 2_234_000 picoseconds. + Weight::from_parts(2_374_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_295_000, 0) + // Minimum execution time: 2_224_000 picoseconds. + Weight::from_parts(2_335_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_284_000 picoseconds. - Weight::from_parts(2_344_000, 0) + // Minimum execution time: 2_184_000 picoseconds. + Weight::from_parts(2_305_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: 43_822_000 picoseconds. - Weight::from_parts(44_784_000, 3593) + // Minimum execution time: 43_151_000 picoseconds. + Weight::from_parts(43_813_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_426_000 picoseconds. - Weight::from_parts(62_288_000, 3964) + // Minimum execution time: 59_853_000 picoseconds. + Weight::from_parts(60_825_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: 26_129_000 picoseconds. - Weight::from_parts(26_690_000, 4096) + // Minimum execution time: 25_599_000 picoseconds. + Weight::from_parts(26_581_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: 18_625_000 picoseconds. - Weight::from_parts(19_167_000, 4036) + // Minimum execution time: 18_165_000 picoseconds. + Weight::from_parts(18_625_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: 21_801_000 picoseconds. - Weight::from_parts(22_292_000, 3850) + // Minimum execution time: 21_491_000 picoseconds. + Weight::from_parts(22_082_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: 18_846_000 picoseconds. - Weight::from_parts(19_317_000, 4025) + // Minimum execution time: 18_675_000 picoseconds. + Weight::from_parts(19_096_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 7aeeb7b44..b641c602a 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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_997_000 picoseconds. - Weight::from_parts(30_979_000, 6175) + // Minimum execution time: 29_145_000 picoseconds. + Weight::from_parts(29_967_000, 6175) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -74,7 +74,7 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `93` // Estimated: `1578` - // Minimum execution time: 5_109_000 picoseconds. + // Minimum execution time: 5_059_000 picoseconds. Weight::from_parts(5_230_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: 5_099_000 picoseconds. - Weight::from_parts(5_230_000, 1578) + // Minimum execution time: 5_130_000 picoseconds. + Weight::from_parts(5_250_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_997_000 picoseconds. - Weight::from_parts(30_979_000, 6175) + // Minimum execution time: 29_145_000 picoseconds. + Weight::from_parts(29_967_000, 6175) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -129,7 +129,7 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `93` // Estimated: `1578` - // Minimum execution time: 5_109_000 picoseconds. + // Minimum execution time: 5_059_000 picoseconds. Weight::from_parts(5_230_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: 5_099_000 picoseconds. - Weight::from_parts(5_230_000, 1578) + // Minimum execution time: 5_130_000 picoseconds. + Weight::from_parts(5_250_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 e59e703ab..64a6b5ae5 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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_628_000 picoseconds. - Weight::from_parts(9_989_000, 3507) + // Minimum execution time: 9_799_000 picoseconds. + Weight::from_parts(10_259_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: 25_148_000 picoseconds. - Weight::from_parts(25_538_000, 3830) + // Minimum execution time: 25_248_000 picoseconds. + Weight::from_parts(25_889_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: 33_954_000 picoseconds. - Weight::from_parts(34_856_000, 3896) + // Minimum execution time: 34_565_000 picoseconds. + Weight::from_parts(35_016_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_667_000 picoseconds. - Weight::from_parts(9_007_000, 3507) + // Minimum execution time: 8_596_000 picoseconds. + Weight::from_parts(9_047_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: 25_188_000 picoseconds. - Weight::from_parts(25_729_000, 4687) + // Minimum execution time: 25_458_000 picoseconds. + Weight::from_parts(26_180_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: 22_542_000 picoseconds. - Weight::from_parts(23_053_000, 4687) + // Minimum execution time: 22_794_000 picoseconds. + Weight::from_parts(23_364_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_628_000 picoseconds. - Weight::from_parts(9_989_000, 3507) + // Minimum execution time: 9_799_000 picoseconds. + Weight::from_parts(10_259_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: 25_148_000 picoseconds. - Weight::from_parts(25_538_000, 3830) + // Minimum execution time: 25_248_000 picoseconds. + Weight::from_parts(25_889_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: 33_954_000 picoseconds. - Weight::from_parts(34_856_000, 3896) + // Minimum execution time: 34_565_000 picoseconds. + Weight::from_parts(35_016_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_667_000 picoseconds. - Weight::from_parts(9_007_000, 3507) + // Minimum execution time: 8_596_000 picoseconds. + Weight::from_parts(9_047_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: 25_188_000 picoseconds. - Weight::from_parts(25_729_000, 4687) + // Minimum execution time: 25_458_000 picoseconds. + Weight::from_parts(26_180_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: 22_542_000 picoseconds. - Weight::from_parts(23_053_000, 4687) + // Minimum execution time: 22_794_000 picoseconds. + Weight::from_parts(23_364_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 5fab1aefe..5a6a896af 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: 2024-06-04, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `4b80713dc969`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` +//! HOSTNAME: `66e77d0da08f`, CPU: `AMD Ryzen 7 5800X 8-Core Processor` //! 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_706_000 picoseconds. - Weight::from_parts(13_976_000, 1624) + // Minimum execution time: 14_217_000 picoseconds. + Weight::from_parts(14_588_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_960_000 picoseconds. - Weight::from_parts(11_311_000, 1690) + // Minimum execution time: 11_501_000 picoseconds. + Weight::from_parts(11_812_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_274_000 picoseconds. - Weight::from_parts(12_604_000, 1657) + // Minimum execution time: 12_654_000 picoseconds. + Weight::from_parts(13_095_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_706_000 picoseconds. - Weight::from_parts(13_976_000, 1624) + // Minimum execution time: 14_217_000 picoseconds. + Weight::from_parts(14_588_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_960_000 picoseconds. - Weight::from_parts(11_311_000, 1690) + // Minimum execution time: 11_501_000 picoseconds. + Weight::from_parts(11_812_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_274_000 picoseconds. - Weight::from_parts(12_604_000, 1657) + // Minimum execution time: 12_654_000 picoseconds. + Weight::from_parts(13_095_000, 1657) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/substrate-node/runtime/src/lib.rs b/substrate-node/runtime/src/lib.rs index 8e2ee7870..723db62f9 100644 --- a/substrate-node/runtime/src/lib.rs +++ b/substrate-node/runtime/src/lib.rs @@ -555,6 +555,7 @@ where frame_system::CheckNonce::::from(index), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), + pallet_smart_contract::types::ContractIdProvides::::new(), ); #[cfg_attr(not(feature = "std"), allow(unused_variables))] @@ -772,6 +773,7 @@ pub type SignedExtra = ( frame_system::CheckNonce, frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, + pallet_smart_contract::types::ContractIdProvides::, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = @@ -790,7 +792,9 @@ pub type Executive = frame_executive::Executive< // All migrations executed on runtime upgrade as a nested tuple of types implementing // `OnRuntimeUpgrade`. -type Migrations = (); +type Migrations = ( + pallet_smart_contract::migrations::v12::MigrateContractLockToContractPaymentState, +); // follows Substrate's non destructive way of eliminating otherwise required // repetion: https://github.com/paritytech/substrate/pull/10592 diff --git a/substrate-node/tests/integration_tests.robot b/substrate-node/tests/integration_tests.robot index d138d64a9..5ceb4c7ca 100644 --- a/substrate-node/tests/integration_tests.robot +++ b/substrate-node/tests/integration_tests.robot @@ -446,6 +446,8 @@ Test Solution Provider # Setup Setup Predefined Account who=Alice Setup Predefined Account who=Bob + Setup Predefined Account who=Charlie + Setup Predefined Account who=Dave Create Farm name=alice_farm Create Node farm_id=${1} hru=${1024} sru=${512} cru=${8} mru=${16} longitude=2.17403 latitude=41.40338 country=Belgium city=Ghent @@ -464,23 +466,6 @@ Test Solution Provider Should Not Be Equal ${solution_provider} ${None} Should Be Equal ${solution_provider}[approved] ${True} - ${balance_charlie_before} = Balance Data who=Charlie - ${balance_dave_before} = Balance Data who=Dave - # Bob will be using the node: let's create a node contract in his name - Create Node Contract node_id=${1} port=${9945} who=Bob solution_provider_id=${1} - Report Contract Resources contract_id=${1} hru=${20} sru=${20} cru=${2} mru=${4} - Add Nru Reports contract_id=${1} nru=${3} - # Wait 6 blocks: after 5 blocks Bob should be billed - Wait X Blocks ${6} - # Cancel the contract so that the bill is distributed and so that the providers get their part - Cancel Node Contract contract_id=${1} who=Bob - - # Verification: both providers should have received their part - ${balance_charlie_after} = Balance Data who=Charlie - ${balance_dave_after} = Balance Data who=Dave - Ensure Account Balance Increased ${balance_charlie_before} ${balance_charlie_after} - Ensure Account Balance Increased ${balance_dave_before} ${balance_dave_after} - Tear Down Multi Node Network Test Client Go integration tests