From d2451e36c3ecb5d354cdb0fb974f5bba5b4811ca Mon Sep 17 00:00:00 2001 From: yahortsaryk Date: Tue, 26 Nov 2024 17:26:43 +0100 Subject: [PATCH] wip: adding billing fingerprint --- pallets/ddc-payouts/src/lib.rs | 76 +++++++++++++++------------- pallets/ddc-verification/src/lib.rs | 30 ++++++----- pallets/ddc-verification/src/mock.rs | 5 +- primitives/src/lib.rs | 1 + primitives/src/traits/payout.rs | 9 ++-- 5 files changed, 65 insertions(+), 56 deletions(-) diff --git a/pallets/ddc-payouts/src/lib.rs b/pallets/ddc-payouts/src/lib.rs index 3f4cd5361..934e80a26 100644 --- a/pallets/ddc-payouts/src/lib.rs +++ b/pallets/ddc-payouts/src/lib.rs @@ -28,8 +28,8 @@ use ddc_primitives::{ pallet::PalletVisitor as PalletVisitorType, payout::PayoutProcessor, }, BatchIndex, BillingReportParams, BucketId, BucketUsage, ClusterId, CustomerCharge, DdcEra, - MMRProof, NodePubKey, NodeUsage, PayableUsageHash, PayoutError, PayoutState, ProviderReward, - MAX_PAYOUT_BATCH_COUNT, MAX_PAYOUT_BATCH_SIZE, MILLICENTS, + Fingerprint, MMRProof, NodePubKey, NodeUsage, PayableUsageHash, PayoutError, PayoutState, + ProviderReward, MAX_PAYOUT_BATCH_COUNT, MAX_PAYOUT_BATCH_SIZE, MILLICENTS, }; use frame_election_provider_support::SortedListProvider; use frame_support::{ @@ -42,7 +42,6 @@ use frame_support::{ use frame_system::pallet_prelude::*; pub use pallet::*; use scale_info::prelude::string::String; -use sp_core::H256; use sp_runtime::{ traits::{Convert, Hash}, AccountId32, PerThing, Perquintill, @@ -66,8 +65,6 @@ pub type VoteScoreOf = ::AccountId, >>::Score; -pub type Fingerprint = H256; - parameter_types! { pub MaxBatchesCount: u16 = MAX_PAYOUT_BATCH_COUNT; pub MaxDust: u128 = MILLICENTS; @@ -238,7 +235,8 @@ pub mod pallet { IncorrectClusterId, ClusterProtocolParamsNotSet, TotalStoredBytesLessThanZero, - FingerprintIsAlreadyCommitted, + BillingFingerprintIsCommitted, + BillingFingerprintDoesNotExist, } #[pallet::storage] @@ -267,8 +265,7 @@ pub mod pallet { pub struct BillingReport { pub state: PayoutState, pub vault: T::AccountId, - pub start_era: i64, - pub end_era: i64, + pub fingerprint: Fingerprint, pub total_customer_charge: CustomerCharge, pub total_distributed_reward: u128, pub total_node_usage: NodeUsage, @@ -285,8 +282,7 @@ pub mod pallet { Self { state: PayoutState::default(), vault: T::PalletId::get().into_account_truncating(), - start_era: Zero::zero(), - end_era: Zero::zero(), + fingerprint: Default::default(), total_customer_charge: CustomerCharge::default(), total_distributed_reward: Zero::zero(), total_node_usage: NodeUsage::default(), @@ -313,7 +309,7 @@ pub mod pallet { } #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] - pub struct BillingReportFingerprint { + pub struct BillingFingerprint { pub cluster_id: ClusterId, pub era_id: DdcEra, pub start_era: i64, @@ -323,7 +319,7 @@ pub mod pallet { pub validators: BTreeSet, } - impl BillingReportFingerprint { + impl BillingFingerprint { fn selective_hash(&self) -> Fingerprint { let mut data = self.cluster_id.encode(); data.extend_from_slice(&self.era_id.encode()); @@ -332,15 +328,15 @@ pub mod pallet { data.extend_from_slice(&self.payers_merkle_root.encode()); data.extend_from_slice(&self.payees_merkle_root.encode()); // we truncate the `validators` field on purpose as it's appendable collection that is - // used for reaching the quorum on the fingerprint + // used for reaching the quorum on the billing fingerprint T::FingerprintHasher::hash(&data).into() } } #[pallet::storage] #[pallet::getter(fn fingerprints)] - pub type Fingerprints = - StorageMap<_, Blake2_128Concat, Fingerprint, BillingReportFingerprint>; + pub type BillingFingerprints = + StorageMap<_, Blake2_128Concat, Fingerprint, BillingFingerprint>; #[pallet::call] impl Pallet {} @@ -593,7 +589,7 @@ pub mod pallet { } impl PayoutProcessor for Pallet { - fn commit_billing_report_fingerprint( + fn commit_billing_fingerprint( validator: T::AccountId, cluster_id: ClusterId, era_id: DdcEra, @@ -606,7 +602,7 @@ pub mod pallet { ensure!(payers_merkle_root != Default::default(), Error::::BadRequest); ensure!(payees_merkle_root != Default::default(), Error::::BadRequest); - let inited_fingerprint = BillingReportFingerprint:: { + let inited_fingerprint = BillingFingerprint:: { cluster_id, era_id, start_era, @@ -617,18 +613,19 @@ pub mod pallet { }; let hash = inited_fingerprint.selective_hash::(); - let mut fingerprint = if let Some(commited_fingerprint) = Fingerprints::::get(hash) { - commited_fingerprint - } else { - inited_fingerprint - }; + let mut fingerprint = + if let Some(commited_fingerprint) = BillingFingerprints::::get(hash) { + commited_fingerprint + } else { + inited_fingerprint + }; ensure!( fingerprint.validators.insert(validator), - Error::::FingerprintIsAlreadyCommitted + Error::::BillingFingerprintIsCommitted ); - Fingerprints::::insert(hash, fingerprint); + BillingFingerprints::::insert(hash, fingerprint); Ok(()) } @@ -636,21 +633,17 @@ pub mod pallet { fn begin_billing_report( cluster_id: ClusterId, era: DdcEra, - start_era: i64, - end_era: i64, + fingerprint: Fingerprint, ) -> DispatchResult { ensure!( ActiveBillingReports::::try_get(cluster_id, era).is_err(), Error::::NotExpectedState ); - ensure!(end_era > start_era, Error::::BadRequest); - let billing_report = BillingReport:: { vault: Self::account_id(), + fingerprint, state: PayoutState::Initialized, - start_era, - end_era, ..Default::default() }; ActiveBillingReports::::insert(cluster_id, era, billing_report); @@ -723,6 +716,9 @@ pub mod pallet { Error::::BatchValidationFailed ); + let fingerprint = BillingFingerprints::::try_get(billing_report.fingerprint) + .map_err(|_| Error::::BillingFingerprintDoesNotExist)?; + let mut updated_billing_report = billing_report; for (_node_key, bucket_ref, customer_usage) in payers { let bucket_id = *bucket_ref; @@ -733,8 +729,8 @@ pub mod pallet { customer_usage, bucket_id, &customer_id, - updated_billing_report.start_era, - updated_billing_report.end_era, + fingerprint.start_era, + fingerprint.end_era, )?; let total_customer_charge = (|| -> Option { customer_charge @@ -1253,11 +1249,23 @@ pub mod pallet { .expect("Rewarding batch to be inserted"); } + let billing_fingerprint = BillingFingerprint:: { + cluster_id: params.cluster_id.clone(), + era_id: params.era.clone(), + start_era: params.start_era.clone(), + end_era: params.end_era.clone(), + payers_merkle_root: Default::default(), + payees_merkle_root: Default::default(), + validators: Default::default(), + }; + + let fingerprint = billing_fingerprint.selective_hash::(); + BillingFingerprints::::insert(fingerprint, billing_fingerprint); + let billing_report = BillingReport:: { vault, - start_era: params.start_era, - end_era: params.end_era, state: params.state, + fingerprint, total_customer_charge: params.total_customer_charge, total_distributed_reward: params.total_distributed_reward, total_node_usage: params.total_node_usage, diff --git a/pallets/ddc-verification/src/lib.rs b/pallets/ddc-verification/src/lib.rs index 9588da4a8..63d22ca5c 100644 --- a/pallets/ddc-verification/src/lib.rs +++ b/pallets/ddc-verification/src/lib.rs @@ -20,8 +20,8 @@ use ddc_primitives::{ ValidatorVisitor, }, ActivityHash, BatchIndex, BillingReportParams, BucketUsage, ClusterId, ClusterStatus, DdcEra, - EraValidation, EraValidationStatus, MMRProof, NodeParams, NodePubKey, NodeUsage, - PayableUsageHash, PayoutState, StorageNodeParams, + EraValidation, EraValidationStatus, MMRProof, NodeParams, NodePubKey, NodeUsage, PayoutState, + StorageNodeParams, }; use frame_support::{ pallet_prelude::*, @@ -84,7 +84,9 @@ pub(crate) type BalanceOf = #[frame_support::pallet] pub mod pallet { - use ddc_primitives::{AggregatorInfo, BucketId, MergeActivityHash, DAC_VERIFICATION_KEY_TYPE}; + use ddc_primitives::{ + AggregatorInfo, BucketId, Fingerprint, MergeActivityHash, DAC_VERIFICATION_KEY_TYPE, + }; use frame_support::PalletId; use sp_core::crypto::AccountId32; use sp_runtime::SaturatedConversion; @@ -1168,15 +1170,14 @@ pub mod pallet { define_payout_step_function!( step_begin_billing_report, prepare_begin_billing_report, - |cluster_id: &ClusterId, (era_id, start_era, end_era)| Call::begin_billing_report { + |cluster_id: &ClusterId, (era_id, fingerprint)| Call::begin_billing_report { cluster_id: *cluster_id, era_id, - start_era, - end_era, + fingerprint }, - |prepared_data: &(DdcEra, _, _)| prepared_data.0, + |prepared_data: &(DdcEra, _)| prepared_data.0, "🗓️ ", - |cluster_id: &ClusterId, (era_id, _, _)| OCWError::BeginBillingReportTransactionError { + |cluster_id: &ClusterId, (era_id, _)| OCWError::BeginBillingReportTransactionError { cluster_id: *cluster_id, era_id, } @@ -1771,9 +1772,11 @@ pub mod pallet { #[allow(dead_code)] pub(crate) fn prepare_begin_billing_report( cluster_id: &ClusterId, - ) -> Result, Vec> { - Ok(Self::get_era_for_payout(cluster_id, EraValidationStatus::ReadyForPayout)) - .map_err(|e| vec![e]) + ) -> Result, Vec> { + // Ok(Self::get_era_for_payout(cluster_id, EraValidationStatus::ReadyForPayout)) + // .map_err(|e| vec![e]) + let era = Self::get_era_for_payout(cluster_id, EraValidationStatus::ReadyForPayout); + Ok(Some((era.unwrap().0, Default::default()))) } pub(crate) fn prepare_begin_charging_customers( @@ -3438,13 +3441,12 @@ pub mod pallet { origin: OriginFor, cluster_id: ClusterId, era_id: DdcEra, - start_era: i64, - end_era: i64, + fingerprint: Fingerprint, ) -> DispatchResult { let sender = ensure_signed(origin.clone())?; ensure!(Self::is_ocw_validator(sender.clone()), Error::::Unauthorized); - T::PayoutProcessor::begin_billing_report(cluster_id, era_id, start_era, end_era)?; + T::PayoutProcessor::begin_billing_report(cluster_id, era_id, fingerprint)?; EraValidations::::try_mutate( cluster_id, diff --git a/pallets/ddc-verification/src/mock.rs b/pallets/ddc-verification/src/mock.rs index 677d2c3ad..17bd47744 100644 --- a/pallets/ddc-verification/src/mock.rs +++ b/pallets/ddc-verification/src/mock.rs @@ -4,7 +4,7 @@ use ddc_primitives::{ crypto, sr25519, traits::{ClusterManager, ClusterQuery}, BucketId, ClusterNodeKind, ClusterNodeState, ClusterNodeStatus, ClusterNodesStats, - ClusterStatus, PayoutError, PayoutState, StorageNodeMode, StorageNodePubKey, + ClusterStatus, Fingerprint, PayoutError, PayoutState, StorageNodeMode, StorageNodePubKey, MAX_PAYOUT_BATCH_COUNT, MAX_PAYOUT_BATCH_SIZE, }; #[cfg(feature = "runtime-benchmarks")] @@ -432,8 +432,7 @@ impl PayoutProcessor for MockPayoutProcessor { fn begin_billing_report( _cluster_id: ClusterId, _era_id: DdcEra, - _start_era: i64, - _end_era: i64, + _fingerprint: Fingerprint, ) -> DispatchResult { unimplemented!() } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 3a36135ee..5673961dc 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -32,6 +32,7 @@ pub type ClusterNodesCount = u16; pub type StorageNodePubKey = AccountId32; pub type ActivityHash = [u8; 32]; // todo: rename to `DeltaUsageHash` pub type PayableUsageHash = H256; +pub type Fingerprint = H256; pub type BatchIndex = u16; pub const AVG_SECONDS_MONTH: i64 = 2630016; // 30.44 * 24.0 * 3600.0; diff --git a/primitives/src/traits/payout.rs b/primitives/src/traits/payout.rs index 0e6e3c8cd..4a33d4e2b 100644 --- a/primitives/src/traits/payout.rs +++ b/primitives/src/traits/payout.rs @@ -1,12 +1,12 @@ use sp_runtime::DispatchResult; use crate::{ - BatchIndex, BillingReportParams, BucketId, BucketUsage, ClusterId, DdcEra, MMRProof, - NodePubKey, NodeUsage, PayableUsageHash, PayoutError, PayoutState, + BatchIndex, BillingReportParams, BucketId, BucketUsage, ClusterId, DdcEra, Fingerprint, + MMRProof, NodePubKey, NodeUsage, PayableUsageHash, PayoutError, PayoutState, }; pub trait PayoutProcessor { - fn commit_billing_report_fingerprint( + fn commit_billing_fingerprint( validator: T::AccountId, cluster_id: ClusterId, era_id: DdcEra, @@ -19,8 +19,7 @@ pub trait PayoutProcessor { fn begin_billing_report( cluster_id: ClusterId, era_id: DdcEra, - start_era: i64, - end_era: i64, + fingerprint: Fingerprint, ) -> DispatchResult; fn begin_charging_customers(