diff --git a/Cargo.lock b/Cargo.lock index f827f6cd3b7..b972f83987b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -936,6 +936,7 @@ dependencies = [ "integer-encoding", "intmap", "itertools", + "lazy_static", "moka", "nohash-hasher", "rand", diff --git a/packages/rs-dpp/src/identity/identity_stub.rs b/packages/rs-dpp/src/identity/identity_stub.rs new file mode 100644 index 00000000000..1af0ef54140 --- /dev/null +++ b/packages/rs-dpp/src/identity/identity_stub.rs @@ -0,0 +1,13 @@ +use std::collections::BTreeMap; +use crate::identifier::Identifier; +use crate::identity::{IdentityPublicKey, KeyID}; +use crate::prelude::Revision; + +/// An identity stub to get only data that is cared about from drive. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct PartialIdentityInfo { + pub id: Identifier, + pub loaded_public_keys: BTreeMap, + pub balance: Option, + pub revision: Option, +} \ No newline at end of file diff --git a/packages/rs-dpp/src/identity/mod.rs b/packages/rs-dpp/src/identity/mod.rs index 28acb8c4873..932af5dfc00 100644 --- a/packages/rs-dpp/src/identity/mod.rs +++ b/packages/rs-dpp/src/identity/mod.rs @@ -2,6 +2,7 @@ pub use credits_converter::*; pub use credits_converter::*; pub use get_biggest_possible_identity::*; pub use identity::*; +pub use identity_stub::*; pub use identity_facade::*; pub use identity_public_key::*; @@ -18,3 +19,4 @@ mod credits_converter; pub mod errors; pub mod factory; pub mod serialize; +mod identity_stub; diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index d1d8614bb88..a3716ae9b01 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -33,6 +33,7 @@ itertools = { version = "0.10.5" } dashcore = { git="https://github.com/dashpay/rust-dashcore", features=["no-std", "secp-recovery", "rand", "signer"], default-features = false, branch="master" } rust_decimal = "1.2.5" rust_decimal_macros = "1.25.0" +lazy_static = "1.4.0" [dependencies.grovedb] git = "https://github.com/dashpay/grovedb" diff --git a/packages/rs-drive/src/drive/document/delete.rs b/packages/rs-drive/src/drive/document/delete.rs index f32044b0b64..69e63c99196 100644 --- a/packages/rs-drive/src/drive/document/delete.rs +++ b/packages/rs-drive/src/drive/document/delete.rs @@ -789,7 +789,7 @@ mod tests { use crate::drive::object_size_info::DocumentInfo::DocumentRefAndSerialization; use crate::drive::Drive; use crate::fee::credits::Creditable; - use crate::fee::default_costs::STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + use crate::fee::default_costs::KnownCostItem::StorageDiskUsageCreditPerByte; use crate::fee_pools::epochs::Epoch; use crate::query::DriveQuery; @@ -1498,7 +1498,8 @@ mod tests { ) .expect("expected to insert a document successfully"); - let added_bytes = fee_result.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let added_bytes = fee_result.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); // We added 1682 bytes assert_eq!(added_bytes, 1682); @@ -1530,8 +1531,8 @@ mod tests { .unwrap(); assert_eq!(*removed_credits, 44959380); - let refund_equivalent_bytes = - removed_credits.to_unsigned() / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let refund_equivalent_bytes = removed_credits.to_unsigned() + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert!(added_bytes > refund_equivalent_bytes); assert_eq!(refund_equivalent_bytes, 1665); // we refunded 1665 instead of 1682 @@ -1579,7 +1580,8 @@ mod tests { ) .expect("expected to insert a document successfully"); - let added_bytes = fee_result.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let added_bytes = fee_result.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); // We added 1682 bytes assert_eq!(added_bytes, 1682); diff --git a/packages/rs-drive/src/drive/document/insert.rs b/packages/rs-drive/src/drive/document/insert.rs index aa5786aeb9a..d6046f48475 100644 --- a/packages/rs-drive/src/drive/document/insert.rs +++ b/packages/rs-drive/src/drive/document/insert.rs @@ -1192,8 +1192,9 @@ mod tests { use crate::drive::object_size_info::DocumentAndContractInfo; use crate::drive::object_size_info::DocumentInfo::DocumentRefAndSerialization; use crate::drive::Drive; - use crate::fee::default_costs::STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + use crate::fee::default_costs::KnownCostItem::StorageDiskUsageCreditPerByte; use crate::fee::op::DriveOperation; + use crate::fee_pools::epochs::Epoch; #[test] fn test_add_dashpay_documents_no_transaction() { @@ -1357,7 +1358,8 @@ mod tests { assert_eq!( fee_result, FeeResult { - storage_fee: 3247 * STORAGE_DISK_USAGE_CREDIT_PER_BYTE, + storage_fee: 3247 + * Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte), processing_fee: 2416920, ..Default::default() } @@ -1406,7 +1408,8 @@ mod tests { assert_eq!( fee_result, FeeResult { - storage_fee: 1428 * STORAGE_DISK_USAGE_CREDIT_PER_BYTE, + storage_fee: 1428 + * Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte), processing_fee: 1570990, ..Default::default() } @@ -1457,7 +1460,8 @@ mod tests { ) .expect("expected to insert a document successfully"); - let added_bytes = storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let added_bytes = + storage_fee / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert_eq!(1428, added_bytes); assert_eq!(145174860, processing_fee); } @@ -1673,7 +1677,8 @@ mod tests { assert_eq!( fee_result, FeeResult { - storage_fee: 1986 * STORAGE_DISK_USAGE_CREDIT_PER_BYTE, + storage_fee: 1986 + * Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte), processing_fee: 2207870, ..Default::default() } diff --git a/packages/rs-drive/src/drive/document/update.rs b/packages/rs-drive/src/drive/document/update.rs index b962bee99a1..577dd3f41c4 100644 --- a/packages/rs-drive/src/drive/document/update.rs +++ b/packages/rs-drive/src/drive/document/update.rs @@ -666,7 +666,8 @@ mod tests { use crate::drive::object_size_info::DocumentInfo::DocumentRefAndSerialization; use crate::drive::{defaults, Drive}; use crate::fee::credits::Creditable; - use crate::fee::default_costs::STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + use crate::fee::default_costs::KnownCostItem::StorageDiskUsageCreditPerByte; + use crate::fee_pools::epochs::Epoch; use crate::query::DriveQuery; use crate::{ common::{json_document_to_cbor, setup_contract, value_to_cbor}, @@ -1391,7 +1392,8 @@ mod tests { true, transaction.as_ref(), ); - let original_bytes = original_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let original_bytes = original_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); let expected_added_bytes = if using_history { //Explanation for 1290 @@ -1552,8 +1554,8 @@ mod tests { .unwrap(); assert_eq!(*removed_credits, 27309075); - let refund_equivalent_bytes = - removed_credits.to_unsigned() / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let refund_equivalent_bytes = removed_credits.to_unsigned() + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert!(expected_added_bytes > refund_equivalent_bytes); assert_eq!(refund_equivalent_bytes, 1011); // we refunded 1011 instead of 1014 @@ -1568,7 +1570,8 @@ mod tests { transaction.as_ref(), ); - let original_bytes = original_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let original_bytes = original_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert_eq!(original_bytes, expected_added_bytes); } @@ -1584,7 +1587,8 @@ mod tests { ); // we both add and remove bytes // this is because trees are added because of indexes, and also removed - let added_bytes = update_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let added_bytes = update_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); let expected_added_bytes = if using_history { 365 } else { 1 }; assert_eq!(added_bytes, expected_added_bytes); @@ -1653,7 +1657,8 @@ mod tests { true, transaction.as_ref(), ); - let original_bytes = original_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let original_bytes = original_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); let expected_added_bytes = if using_history { 1290 } else { 1014 }; assert_eq!(original_bytes, expected_added_bytes); if !using_history { @@ -1674,8 +1679,8 @@ mod tests { .unwrap(); assert_eq!(*removed_credits, 27309075); - let refund_equivalent_bytes = - removed_credits.to_unsigned() / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let refund_equivalent_bytes = removed_credits.to_unsigned() + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert!(expected_added_bytes > refund_equivalent_bytes); assert_eq!(refund_equivalent_bytes, 1011); // we refunded 1011 instead of 1014 @@ -1690,7 +1695,8 @@ mod tests { transaction.as_ref(), ); - let original_bytes = original_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let original_bytes = original_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert_eq!(original_bytes, expected_added_bytes); } @@ -1706,7 +1712,8 @@ mod tests { ); // we both add and remove bytes // this is because trees are added because of indexes, and also removed - let added_bytes = update_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let added_bytes = update_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); let removed_credits = update_fees .fee_refunds @@ -1721,8 +1728,8 @@ mod tests { let expected_removed_credits = if using_history { 16266750 } else { 16212825 }; assert_eq!(*removed_credits, expected_removed_credits); - let refund_equivalent_bytes = - removed_credits.to_unsigned() / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let refund_equivalent_bytes = removed_credits.to_unsigned() + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); assert!(expected_added_bytes > refund_equivalent_bytes); let expected_remove_bytes = if using_history { 602 } else { 600 }; @@ -1832,7 +1839,8 @@ mod tests { false, transaction.as_ref(), ); - let original_bytes = original_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let original_bytes = original_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); let expected_added_bytes = if using_history { //Explanation for 1290 @@ -1987,7 +1995,8 @@ mod tests { ); // we both add and remove bytes // this is because trees are added because of indexes, and also removed - let added_bytes = update_fees.storage_fee / STORAGE_DISK_USAGE_CREDIT_PER_BYTE; + let added_bytes = update_fees.storage_fee + / Epoch::new(0).cost_for_known_cost_item(StorageDiskUsageCreditPerByte); let expected_added_bytes = if using_history { 1291 } else { 1015 }; assert_eq!(added_bytes, expected_added_bytes); diff --git a/packages/rs-drive/src/drive/identity/fetch/balance.rs b/packages/rs-drive/src/drive/identity/fetch/balance.rs new file mode 100644 index 00000000000..21137ca65e8 --- /dev/null +++ b/packages/rs-drive/src/drive/identity/fetch/balance.rs @@ -0,0 +1,138 @@ +use crate::drive::block_info::BlockInfo; +use crate::drive::defaults::PROTOCOL_VERSION; +use crate::drive::identity::key::fetch::{IdentityKeysRequest, KeyIDIdentityPublicKeyPairBTreeMap}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fee::credits::Credits; +use crate::fee::default_costs::KnownCostItem::FetchIdentityBalanceProcessingCost; +use crate::fee::epoch::EpochIndex; +use crate::fee::op::DriveOperation; +use crate::fee::result::FeeResult; +use crate::fee_pools::epochs::Epoch; +use dpp::identifier::Identifier; +use dpp::identity::{Identity, PartialIdentityInfo}; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the Identity's balance as PartialIdentityInfo from the backing store + /// Passing apply as false get the estimated cost instead + pub fn fetch_identity_with_balance( + &self, + identity_id: [u8; 32], + transaction: TransactionArg, + ) -> Result, Error> { + let mut drive_operations: Vec = vec![]; + Ok(self + .fetch_identity_balance_operations( + identity_id, + true, + transaction, + &mut drive_operations, + )? + .map(|balance| PartialIdentityInfo { + id: Identifier::new(identity_id), + loaded_public_keys: Default::default(), + balance: Some(balance), + revision: None, + })) + } + + /// Fetches the Identity's balance as PartialIdentityInfo from the backing store + /// Passing apply as false get the estimated cost instead + pub fn fetch_identity_with_balance_with_cost( + &self, + identity_id: [u8; 32], + apply: bool, + epoch: &Epoch, + transaction: TransactionArg, + ) -> Result<(Option, FeeResult), Error> { + let balance_cost = epoch.cost_for_known_cost_item(FetchIdentityBalanceProcessingCost); + if apply == false { + return Ok((None, FeeResult::new_from_processing_fee(balance_cost))); + } + let mut drive_operations: Vec = vec![]; + Ok(( + self.fetch_identity_balance_operations( + identity_id, + apply, + transaction, + &mut drive_operations, + )? + .map(|balance| PartialIdentityInfo { + id: Identifier::new(identity_id), + loaded_public_keys: Default::default(), + balance: Some(balance), + revision: None, + }), + FeeResult::new_from_processing_fee(balance_cost), + )) + } + + /// Fetches the Identity's balance with keys as PartialIdentityInfo from the backing store + /// Passing apply as false get the estimated cost instead + pub fn fetch_identity_balance_with_keys( + &self, + identity_key_request: IdentityKeysRequest, + transaction: TransactionArg, + ) -> Result, Error> { + let id = Identifier::new(identity_key_request.identity_id); + let balance = + self.fetch_identity_balance(identity_key_request.identity_id, true, transaction)?; + let Some(balance) = balance else { + return Ok(None); + }; + + let loaded_public_keys = self.fetch_identity_keys::( + identity_key_request, + transaction, + )?; + Ok(Some(PartialIdentityInfo { + id, + loaded_public_keys, + balance: Some(balance), + revision: None, + })) + } + + /// Fetches the Identity's balance with keys as PartialIdentityInfo from the backing store + /// Passing apply as false get the estimated cost instead + pub fn fetch_identity_balance_with_keys_with_cost( + &self, + identity_key_request: IdentityKeysRequest, + apply: bool, + epoch: &Epoch, + transaction: TransactionArg, + ) -> Result<(Option, FeeResult), Error> { + let balance_cost = epoch.cost_for_known_cost_item(FetchIdentityBalanceProcessingCost); + if apply == false { + let keys_cost = identity_key_request.processing_cost(epoch)?; + return Ok(( + None, + FeeResult::new_from_processing_fee(balance_cost + keys_cost), + )); + } + // let's start by getting the balance + let id = Identifier::new(identity_key_request.identity_id); + let balance = + self.fetch_identity_balance(identity_key_request.identity_id, apply, transaction)?; + let Some(balance) = balance else { + return Ok((None, FeeResult::new_from_processing_fee(balance_cost))); + }; + + let keys_cost = identity_key_request.processing_cost(epoch)?; + + let loaded_public_keys = self.fetch_identity_keys::( + identity_key_request, + transaction, + )?; + Ok(( + Some(PartialIdentityInfo { + id, + loaded_public_keys, + balance: Some(balance), + revision: None, + }), + FeeResult::new_from_processing_fee(balance_cost + keys_cost), + )) + } +} diff --git a/packages/rs-drive/src/drive/identity/fetch_by_public_key_hashes.rs b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes.rs similarity index 96% rename from packages/rs-drive/src/drive/identity/fetch_by_public_key_hashes.rs rename to packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes.rs index 3ea7125727a..24325364e95 100644 --- a/packages/rs-drive/src/drive/identity/fetch_by_public_key_hashes.rs +++ b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes.rs @@ -266,7 +266,16 @@ impl Drive { transaction, drive_operations, )?; - todo!() + identity_ids + .into_iter() + .map(|(public_key_hash, maybe_identity_id)| { + let identity = maybe_identity_id + .map(|identity_id| self.fetch_full_identity(identity_id, transaction)) + .transpose()? + .flatten(); + Ok((public_key_hash, identity)) + }) + .collect::>, Error>>() } /// The query for the identity revision diff --git a/packages/rs-drive/src/drive/identity/fetch/full_identity.rs b/packages/rs-drive/src/drive/identity/fetch/full_identity.rs new file mode 100644 index 00000000000..6038a152b0d --- /dev/null +++ b/packages/rs-drive/src/drive/identity/fetch/full_identity.rs @@ -0,0 +1,206 @@ +use crate::drive::balances::balance_path; +use crate::drive::defaults::PROTOCOL_VERSION; +use crate::drive::identity::key::fetch::IdentityKeysRequest; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fee::calculate_fee; +use crate::fee::op::DriveOperation; +use crate::fee::result::FeeResult; +use crate::fee_pools::epochs::Epoch; +use dpp::identifier::Identifier; +use dpp::identity::Identity; +use dpp::prelude::Revision; +use grovedb::query_result_type::Path; +use grovedb::{PathQuery, TransactionArg}; +use std::collections::{BTreeMap, BTreeSet}; + +impl Drive { + /// Fetches an identity with all its information and + /// the cost it took from storage. + pub fn fetch_full_identity_with_costs( + &self, + identity_id: [u8; 32], + epoch: &Epoch, + transaction: TransactionArg, + ) -> Result<(Option, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let maybe_identity = + self.fetch_full_identity_operations(identity_id, transaction, &mut drive_operations)?; + let fee = calculate_fee(None, Some(drive_operations), epoch)?; + Ok((maybe_identity, fee)) + } + + /// The query getting all keys and balance and revision + pub fn full_identity_query(identity_id: [u8; 32]) -> Result { + let balance_query = Self::identity_balance_query(identity_id); + let revision_query = Self::identity_revision_query(identity_id); + let key_request = IdentityKeysRequest::new_all_keys_query(identity_id); + let all_keys_query = key_request.into_path_query(); + PathQuery::merge(vec![&balance_query, &revision_query, &all_keys_query]) + .map_err(Error::GroveDB) + } + + /// The query getting all keys and balance and revision + pub fn full_identities_query(identity_ids: Vec<[u8; 32]>) -> Result { + let path_queries: Vec = identity_ids + .into_iter() + .map(|identity_id| Self::full_identity_query(identity_id)) + .collect::, Error>>()?; + PathQuery::merge(path_queries.iter().map(|query| query).collect()).map_err(Error::GroveDB) + } + + /// Fetches an identity with all its information from storage. + pub fn fetch_proved_full_identity( + &self, + identity_id: [u8; 32], + transaction: TransactionArg, + ) -> Result>, Error> { + let mut drive_operations: Vec = vec![]; + let query = Self::full_identity_query(identity_id)?; + let result = self.grove_get_proved_path_query(&query, transaction, &mut drive_operations); + match result { + Ok(r) => Ok(Some(r)), + Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) + | Err(Error::GroveDB(grovedb::Error::PathParentLayerNotFound(_))) + | Err(Error::GroveDB(grovedb::Error::PathNotFound(_))) => Ok(None), + Err(e) => Err(e), + } + } + + /// Fetches an identity with all its information from storage. + pub fn fetch_proved_full_identities( + &self, + identity_ids: Vec<[u8; 32]>, + transaction: TransactionArg, + ) -> Result>, Error> { + let mut drive_operations: Vec = vec![]; + let query = Self::full_identities_query(identity_ids)?; + let result = self.grove_get_proved_path_query(&query, transaction, &mut drive_operations); + match result { + Ok(r) => Ok(Some(r)), + Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) + | Err(Error::GroveDB(grovedb::Error::PathParentLayerNotFound(_))) + | Err(Error::GroveDB(grovedb::Error::PathNotFound(_))) => Ok(None), + Err(e) => Err(e), + } + } + + // /// Fetches identities with all its information from storage. + // #[deprecated(since = "0.24.0", note = "please use exact fetching")] + // pub fn fetch_full_identities_efficient( + // &self, + // identity_ids: Vec<[u8; 32]>, + // transaction: TransactionArg, + // ) -> Result>, Error> { + // let mut drive_operations: Vec = vec![]; + // let query = Self::full_identities_query(identity_ids)?; + // let result = + // self.grove_get_path_query_with_optional(&query, transaction, &mut drive_operations)?; + // + // let balances_path = balance_path(); + // // Let's do a first pass to get identities from balances + // let mut identities :BTreeMap<[u8; 32], Option> = result.iter().filter_map( + // |(path, key, element)| { + // if path == balances_path { + // let identity_id = key.try_into().map_err(|_| Error::Drive(DriveError::CorruptedDriveState("balance key not 32 bytes".to_string())))?; + // if &Some(balance) = element { + // Some((identity_id, Identity { + // protocol_version: PROTOCOL_VERSION, + // id: identity_id, + // public_keys: Default::default(), + // balance, + // revision: Revision::MAX, + // asset_lock_proof: None, + // metadata: None, + // })) + // } else { + // Some((identity_id, None)) + // } + // } else { + // None + // } + // } + // ).collect()?; + // + // result.into_iter().try_for_each( + // |(path, key, element)| { + // if path != balances_path { + // if let Some(element) = element { + // // we need to get the identity_id from the path which will be the second item (1) + // // of the path + // let identity_id: [u8;32] = path.get(1).ok_or(Error::Drive(DriveError::CorruptedDriveState("path much contain identity id".to_string())))?.try_into() + // .try_into().map_err(|_| Error::Drive(DriveError::CorruptedDriveState("identity id not 32 bytes".to_string())))?; + // let mut identity = identities.get_mut(&identity_id).ok_or(); + // } + // } + // } + // )?; + // Ok(identities) + // } + + /// Fetches identities with all its information from storage. + #[deprecated(since = "0.24.0", note = "please use exact fetching")] + pub fn fetch_full_identities( + &self, + identity_ids: Vec<[u8; 32]>, + transaction: TransactionArg, + ) -> Result>, Error> { + identity_ids + .into_iter() + .map(|identity_id| { + Ok(( + identity_id, + self.fetch_full_identity(identity_id, transaction)?, + )) + }) + .collect() + } + + /// Fetches an identity with all its information from storage. + pub fn fetch_full_identity( + &self, + identity_id: [u8; 32], + transaction: TransactionArg, + ) -> Result, Error> { + let mut drive_operations: Vec = vec![]; + self.fetch_full_identity_operations(identity_id, transaction, &mut drive_operations) + } + + /// Given an identity, fetches the identity with its flags from storage. + pub fn fetch_full_identity_operations( + &self, + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + ) -> Result, Error> { + // let's start by getting the balance + let balance = self.fetch_identity_balance_operations( + identity_id, + true, + transaction, + drive_operations, + )?; + if balance.is_none() { + return Ok(None); + } + let balance = balance.unwrap(); + let revision = self + .fetch_identity_revision_operations(identity_id, true, transaction, drive_operations)? + .ok_or(Error::Drive(DriveError::CorruptedDriveState( + "revision not found on identity".to_string(), + )))?; + + let public_keys = + self.fetch_all_identity_keys_operations(identity_id, transaction, drive_operations)?; + Ok(Some(Identity { + protocol_version: PROTOCOL_VERSION, + id: Identifier::new(identity_id), + public_keys, + balance, + revision, + asset_lock_proof: None, + metadata: None, + })) + } +} diff --git a/packages/rs-drive/src/drive/identity/fetch.rs b/packages/rs-drive/src/drive/identity/fetch/mod.rs similarity index 51% rename from packages/rs-drive/src/drive/identity/fetch.rs rename to packages/rs-drive/src/drive/identity/fetch/mod.rs index cfafde0f896..b38243d85e4 100644 --- a/packages/rs-drive/src/drive/identity/fetch.rs +++ b/packages/rs-drive/src/drive/identity/fetch/mod.rs @@ -29,34 +29,12 @@ use grovedb::{PathQuery, SizedQuery, TransactionArg}; use integer_encoding::VarInt; use std::collections::BTreeMap; -impl Drive { - /// Fetches the Identity's balance as an identity stub from the backing store - /// Passing apply as false get the estimated cost instead - pub fn fetch_identity_stub_with_balance( - &self, - identity_id: [u8; 32], - apply: bool, - transaction: TransactionArg, - ) -> Result, Error> { - let mut drive_operations: Vec = vec![]; - Ok(self - .fetch_identity_balance_operations( - identity_id, - apply, - transaction, - &mut drive_operations, - )? - .map(|balance| Identity { - protocol_version: PROTOCOL_VERSION, - id: Identifier::new(identity_id), - public_keys: Default::default(), - balance, - revision: 0, - asset_lock_proof: None, - metadata: None, - })) - } +mod balance; +mod fetch_by_public_key_hashes; +mod full_identity; +mod revision; +impl Drive { /// The query for the identity revision pub fn identity_revision_query(identity_id: [u8; 32]) -> PathQuery { let identity_path = identity_path_vec(identity_id.as_slice()); @@ -72,264 +50,6 @@ impl Drive { } } - /// Fetches the Identity's revision from the backing store - /// Passing apply as false get the estimated cost instead - pub fn fetch_identity_revision( - &self, - identity_id: [u8; 32], - apply: bool, - transaction: TransactionArg, - ) -> Result, Error> { - let mut drive_operations: Vec = vec![]; - self.fetch_identity_revision_operations( - identity_id, - apply, - transaction, - &mut drive_operations, - ) - } - - /// Fetches the Identity's revision from the backing store - /// Passing apply as false get the estimated cost instead - pub fn fetch_identity_revision_with_fees( - &self, - identity_id: [u8; 32], - block_info: &BlockInfo, - apply: bool, - transaction: TransactionArg, - ) -> Result<(Option, FeeResult), Error> { - let mut drive_operations: Vec = vec![]; - let value = self.fetch_identity_revision_operations( - identity_id, - apply, - transaction, - &mut drive_operations, - )?; - let fees = calculate_fee(None, Some(drive_operations), &block_info.epoch)?; - Ok((value, fees)) - } - - /// Creates the operations to get Identity's revision from the backing store - /// This gets operations based on apply flag (stateful vs stateless) - pub(crate) fn fetch_identity_revision_operations( - &self, - identity_id: [u8; 32], - apply: bool, - transaction: TransactionArg, - drive_operations: &mut Vec, - ) -> Result, Error> { - let direct_query_type = if apply { - DirectQueryType::StatefulDirectQuery - } else { - DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: false, - query_target: QueryTargetValue(1), - } - }; - let identity_path = identity_path(identity_id.as_slice()); - match self.grove_get_raw( - identity_path, - &[IdentityTreeRevision as u8], - direct_query_type, - transaction, - drive_operations, - ) { - Ok(Some(Item(encoded_revision, _))) => { - let revision = u64::from_be_bytes(encoded_revision.try_into().map_err(|_| { - Error::Drive(DriveError::CorruptedElementType( - "identity revision was not 8 bytes as expected", - )) - })?); - - Ok(Some(revision)) - } - - Ok(None) => Ok(None), - - Ok(Some(..)) => Err(Error::Drive(DriveError::CorruptedElementType( - "identity revision was present but was not identified as an item", - ))), - - Err(e) => Err(e), - } - } - - /// Given an identity, fetches the identity with its flags from storage. - pub fn fetch_identity_balance_with_keys( - &self, - identity_key_request: IdentityKeysRequest, - transaction: TransactionArg, - ) -> Result, Error> { - // let's start by getting the balance - let id = Identifier::new(identity_key_request.identity_id); - let balance = - self.fetch_identity_balance(identity_key_request.identity_id, true, transaction)?; - if balance.is_none() { - return Ok(None); - } - let balance = balance.unwrap(); - - let public_keys = self.fetch_identity_keys::( - identity_key_request, - transaction, - )?; - Ok(Some(Identity { - protocol_version: PROTOCOL_VERSION, - id, - public_keys, - balance, - revision: u64::MAX, - asset_lock_proof: None, - metadata: None, - })) - } - - /// Fetches an identity with all its information and - /// the cost it took from storage. - pub fn fetch_full_identity_with_costs( - &self, - identity_id: [u8; 32], - epoch: &Epoch, - transaction: TransactionArg, - ) -> Result<(Option, FeeResult), Error> { - let mut drive_operations: Vec = vec![]; - let maybe_identity = - self.fetch_full_identity_operations(identity_id, transaction, &mut drive_operations)?; - let fee = calculate_fee(None, Some(drive_operations), epoch)?; - Ok((maybe_identity, fee)) - } - - /// The query getting all keys and balance and revision - pub fn full_identity_query(identity_id: [u8; 32]) -> Result { - let balance_query = Self::identity_balance_query(identity_id); - let revision_query = Self::identity_revision_query(identity_id); - let key_request = IdentityKeysRequest::new_all_keys_query(identity_id); - let all_keys_query = key_request.into_path_query(); - PathQuery::merge(vec![&balance_query, &revision_query, &all_keys_query]) - .map_err(Error::GroveDB) - } - - /// The query getting all keys and balance and revision - pub fn full_identities_query(identity_ids: Vec<[u8; 32]>) -> Result { - let path_queries: Vec = identity_ids - .into_iter() - .map(|identity_id| Self::full_identity_query(identity_id)) - .collect::, Error>>()?; - PathQuery::merge(path_queries.iter().map(|query| query).collect()).map_err(Error::GroveDB) - } - - /// Fetches an identity with all its information from storage. - pub fn fetch_proved_full_identity( - &self, - identity_id: [u8; 32], - transaction: TransactionArg, - ) -> Result>, Error> { - let mut drive_operations: Vec = vec![]; - let query = Self::full_identity_query(identity_id)?; - let result = self.grove_get_proved_path_query(&query, transaction, &mut drive_operations); - match result { - Ok(r) => Ok(Some(r)), - Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) - | Err(Error::GroveDB(grovedb::Error::PathParentLayerNotFound(_))) - | Err(Error::GroveDB(grovedb::Error::PathNotFound(_))) => Ok(None), - Err(e) => Err(e), - } - } - - /// Fetches an identity with all its information from storage. - pub fn fetch_proved_full_identities( - &self, - identity_ids: Vec<[u8; 32]>, - transaction: TransactionArg, - ) -> Result>, Error> { - let mut drive_operations: Vec = vec![]; - let query = Self::full_identities_query(identity_ids)?; - let result = self.grove_get_proved_path_query(&query, transaction, &mut drive_operations); - match result { - Ok(r) => Ok(Some(r)), - Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) - | Err(Error::GroveDB(grovedb::Error::PathParentLayerNotFound(_))) - | Err(Error::GroveDB(grovedb::Error::PathNotFound(_))) => Ok(None), - Err(e) => Err(e), - } - } - - // /// Fetches an identity with all its information from storage. - // pub fn fetch_full_identities( - // &self, - // identity_ids: Vec<[u8; 32]>, - // transaction: TransactionArg, - // ) -> Result, Error> { - // let mut drive_operations: Vec = vec![]; - // let query = Self::full_identities_query(identity_ids)?; - // let result = self.grove_get_path_query_with_optional(&query, transaction, &mut drive_operations)?; - // result.into_iter().map(|(_, key, element)| { - // - // }).collect() - // } - - // /// Fetches identities with all its information from storage. - // pub fn fetch_full_identities_operations( - // &self, - // identity_ids: Vec<[u8; 32]>, - // transaction: TransactionArg, - // drive_operations: &mut Vec, - // ) -> Result>, Error> { - // let mut drive_operations: Vec = vec![]; - // let query = Self::full_identities_query(identity_ids)?; - // let result = self.grove_get_path_query_with_optional(&query, transaction, &mut drive_operations)?; - // result.into_iter().map(|(_, key, element)| { - // - // }).collect() - // } - - /// Fetches an identity with all its information from storage. - pub fn fetch_full_identity( - &self, - identity_id: [u8; 32], - transaction: TransactionArg, - ) -> Result, Error> { - let mut drive_operations: Vec = vec![]; - self.fetch_full_identity_operations(identity_id, transaction, &mut drive_operations) - } - - /// Given an identity, fetches the identity with its flags from storage. - pub fn fetch_full_identity_operations( - &self, - identity_id: [u8; 32], - transaction: TransactionArg, - drive_operations: &mut Vec, - ) -> Result, Error> { - // let's start by getting the balance - let balance = self.fetch_identity_balance_operations( - identity_id, - true, - transaction, - drive_operations, - )?; - if balance.is_none() { - return Ok(None); - } - let balance = balance.unwrap(); - let revision = self - .fetch_identity_revision_operations(identity_id, true, transaction, drive_operations)? - .ok_or(Error::Drive(DriveError::CorruptedDriveState( - "revision not found on identity".to_string(), - )))?; - - let public_keys = - self.fetch_all_identity_keys_operations(identity_id, transaction, drive_operations)?; - Ok(Some(Identity { - protocol_version: PROTOCOL_VERSION, - id: Identifier::new(identity_id), - public_keys, - balance, - revision, - asset_lock_proof: None, - metadata: None, - })) - } - /// Given a vector of identities, fetches the identities from storage. pub fn verify_all_identities_exist( &self, diff --git a/packages/rs-drive/src/drive/identity/fetch/revision.rs b/packages/rs-drive/src/drive/identity/fetch/revision.rs new file mode 100644 index 00000000000..1e93d0d9de9 --- /dev/null +++ b/packages/rs-drive/src/drive/identity/fetch/revision.rs @@ -0,0 +1,97 @@ +use crate::drive::block_info::BlockInfo; +use crate::drive::grove_operations::DirectQueryType; +use crate::drive::grove_operations::QueryTarget::QueryTargetValue; +use crate::drive::identity::identity_path; +use crate::drive::identity::IdentityRootStructure::IdentityTreeRevision; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fee::calculate_fee; +use crate::fee::op::DriveOperation; +use crate::fee::result::FeeResult; +use grovedb::Element::Item; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the Identity's revision from the backing store + /// Passing apply as false get the estimated cost instead + pub fn fetch_identity_revision( + &self, + identity_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + ) -> Result, Error> { + let mut drive_operations: Vec = vec![]; + self.fetch_identity_revision_operations( + identity_id, + apply, + transaction, + &mut drive_operations, + ) + } + + /// Fetches the Identity's revision from the backing store + /// Passing apply as false get the estimated cost instead + pub fn fetch_identity_revision_with_fees( + &self, + identity_id: [u8; 32], + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + ) -> Result<(Option, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identity_revision_operations( + identity_id, + apply, + transaction, + &mut drive_operations, + )?; + let fees = calculate_fee(None, Some(drive_operations), &block_info.epoch)?; + Ok((value, fees)) + } + + /// Creates the operations to get Identity's revision from the backing store + /// This gets operations based on apply flag (stateful vs stateless) + pub(crate) fn fetch_identity_revision_operations( + &self, + identity_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + ) -> Result, Error> { + let direct_query_type = if apply { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_using_sums: false, + query_target: QueryTargetValue(1), + } + }; + let identity_path = identity_path(identity_id.as_slice()); + match self.grove_get_raw( + identity_path, + &[IdentityTreeRevision as u8], + direct_query_type, + transaction, + drive_operations, + ) { + Ok(Some(Item(encoded_revision, _))) => { + let revision = u64::from_be_bytes(encoded_revision.try_into().map_err(|_| { + Error::Drive(DriveError::CorruptedElementType( + "identity revision was not 8 bytes as expected", + )) + })?); + + Ok(Some(revision)) + } + + Ok(None) => Ok(None), + + Ok(Some(..)) => Err(Error::Drive(DriveError::CorruptedElementType( + "identity revision was present but was not identified as an item", + ))), + + Err(e) => Err(e), + } + } +} diff --git a/packages/rs-drive/src/drive/identity/key/fetch.rs b/packages/rs-drive/src/drive/identity/key/fetch.rs index 9f2481c0bcc..f321865fea1 100644 --- a/packages/rs-drive/src/drive/identity/key/fetch.rs +++ b/packages/rs-drive/src/drive/identity/key/fetch.rs @@ -6,9 +6,13 @@ use crate::drive::identity::key::fetch::KeyKindRequestType::{ use crate::drive::identity::key::fetch::KeyRequestType::{AllKeys, SearchKey, SpecificKeys}; use crate::drive::Drive; use crate::error::drive::DriveError; +use crate::error::fee::FeeError; use crate::error::identity::IdentityError; use crate::error::Error; +use crate::fee::credits::Credits; +use crate::fee::default_costs::KnownCostItem::FetchSingleIdentityKeyProcessingCost; use crate::fee::op::DriveOperation; +use crate::fee_pools::epochs::Epoch; use crate::query::{Query, QueryItem}; use dpp::identity::{KeyID, Purpose, SecurityLevel}; use dpp::prelude::IdentityPublicKey; @@ -247,6 +251,17 @@ pub struct IdentityKeysRequest { } impl IdentityKeysRequest { + /// Gets the processing cost of an identity keys request + pub fn processing_cost(&self, epoch: &Epoch) -> Result { + match &self.request_type { + AllKeys => Err(Error::Fee(FeeError::OperationNotAllowed( + "You can not get costs for requesting all keys", + ))), + SpecificKeys(keys) => Ok(keys.len() as u64 + * epoch.cost_for_known_cost_item(FetchSingleIdentityKeyProcessingCost)), + SearchKey(search) => todo!(), + } + } /// Make a request for all current keys for the identity pub fn new_all_current_keys_query(identity_id: [u8; 32]) -> Self { let mut sec_btree_map = BTreeMap::new(); diff --git a/packages/rs-drive/src/drive/identity/mod.rs b/packages/rs-drive/src/drive/identity/mod.rs index 8ac0612ac9d..e37c921119a 100644 --- a/packages/rs-drive/src/drive/identity/mod.rs +++ b/packages/rs-drive/src/drive/identity/mod.rs @@ -44,7 +44,6 @@ mod balance; mod contract_info; mod estimation_costs; mod fetch; -mod fetch_by_public_key_hashes; mod insert; mod key; mod update; diff --git a/packages/rs-drive/src/error/fee.rs b/packages/rs-drive/src/error/fee.rs index d74936a4caf..8878a7bd5a6 100644 --- a/packages/rs-drive/src/error/fee.rs +++ b/packages/rs-drive/src/error/fee.rs @@ -10,6 +10,10 @@ pub enum FeeError { #[error("insufficient balance error: {0}")] InsufficientBalance(&'static str), + /// Operation not allowed error + #[error("operation not allowed error: {0}")] + OperationNotAllowed(&'static str), + /// Corrupted estimated layer info missing error #[error("corrupted estimated layer info missing error: {0}")] CorruptedEstimatedLayerInfoMissing(String), diff --git a/packages/rs-drive/src/fee/default_costs.rs b/packages/rs-drive/src/fee/default_costs.rs deleted file mode 100644 index 00fe6cec463..00000000000 --- a/packages/rs-drive/src/fee/default_costs.rs +++ /dev/null @@ -1,46 +0,0 @@ -// MIT LICENSE -// -// Copyright (c) 2021 Dash Core Group -// -// Permission is hereby granted, free of charge, to any -// person obtaining a copy of this software and associated -// documentation files (the "Software"), to deal in the -// Software without restriction, including without -// limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software -// is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice -// shall be included in all copies or substantial portions -// of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// - -//! Fee costs -//! -//! Fee costs for Drive (GroveDB) operations -//! - -/// Storage disk usage credit per byte -pub(crate) const STORAGE_DISK_USAGE_CREDIT_PER_BYTE: u64 = 27000; -/// Storage processing credit per byte -pub(crate) const STORAGE_PROCESSING_CREDIT_PER_BYTE: u64 = 400; -/// Storage load credit per byte -pub(crate) const STORAGE_LOAD_CREDIT_PER_BYTE: u64 = 400; -/// Non storage load credit per byte -pub(crate) const NON_STORAGE_LOAD_CREDIT_PER_BYTE: u64 = 30; -/// Query credit per byte -pub(crate) const QUERY_CREDIT_PER_BYTE: u64 = 10; -/// Storage seek cost -pub(crate) const STORAGE_SEEK_COST: u64 = 4000; diff --git a/packages/rs-drive/src/fee/default_costs/mod.rs b/packages/rs-drive/src/fee/default_costs/mod.rs new file mode 100644 index 00000000000..04654a4d15b --- /dev/null +++ b/packages/rs-drive/src/fee/default_costs/mod.rs @@ -0,0 +1,98 @@ +// MIT LICENSE +// +// Copyright (c) 2021 Dash Core Group +// +// Permission is hereby granted, free of charge, to any +// person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the +// Software without restriction, including without +// limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software +// is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice +// shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +//! Fee costs +//! +//! Fee costs for Drive (GroveDB) operations +//! + +use crate::fee::epoch::EpochIndex; +use crate::fee_pools::epochs::Epoch; +use lazy_static::lazy_static; +use std::collections::HashMap; + +/// A Known Cost Item is an item that changes costs depending on the Epoch +#[derive(Eq, PartialEq, Copy, Clone, Hash)] +pub enum KnownCostItem { + /// The storage cost used when writing bytes + StorageDiskUsageCreditPerByte, + /// The processing cost used when writing bytes + StorageProcessingCreditPerByte, + /// The processing cost used when loading bytes from storage + StorageLoadCreditPerByte, + /// The processing cost used when loading bytes not from storage + NonStorageLoadCreditPerByte, + /// The cost used when performing a disk seek + StorageSeekCost, + // The following are set costs of routine operations + /// The cost for fetching an identity balance + FetchIdentityBalanceProcessingCost, + /// The cost for fetching an identity key + FetchSingleIdentityKeyProcessingCost, +} + +const EPOCH_COST_UPDATE_VERSIONS: [u16; 1] = [0]; + +lazy_static! { + static ref EPOCH_COSTS: HashMap> = [( + 0, + [ + (KnownCostItem::StorageDiskUsageCreditPerByte, 27000), + (KnownCostItem::StorageProcessingCreditPerByte, 400), + (KnownCostItem::StorageLoadCreditPerByte, 400), + (KnownCostItem::NonStorageLoadCreditPerByte, 30), + (KnownCostItem::StorageSeekCost, 4000), + (KnownCostItem::FetchIdentityBalanceProcessingCost, 10000), + (KnownCostItem::FetchSingleIdentityKeyProcessingCost, 10000), + ] + .into_iter() + .collect() + ),] + .into_iter() + .collect(); +} + +impl Epoch { + //todo: should just have a static lookup table + /// Get the closest epoch in the past that has a cost table + /// This is where the base costs last changed + fn get_closest_epoch_index_cost_update_version(&self) -> EpochIndex { + match EPOCH_COST_UPDATE_VERSIONS.binary_search(&self.index) { + Ok(_) => self.index, + Err(pos) => EPOCH_COST_UPDATE_VERSIONS[pos - 1], + } + } + + /// Get the cost for the known cost item + pub fn cost_for_known_cost_item(&self, cost_item: KnownCostItem) -> u64 { + let epoch = self.get_closest_epoch_index_cost_update_version(); + let specific_epoch_costs = EPOCH_COSTS.get(&epoch).unwrap(); + *specific_epoch_costs.get(&cost_item).unwrap() + } +} diff --git a/packages/rs-drive/src/fee/op.rs b/packages/rs-drive/src/fee/op.rs index a8970ccf10f..c3314323b1c 100644 --- a/packages/rs-drive/src/fee/op.rs +++ b/packages/rs-drive/src/fee/op.rs @@ -45,9 +45,9 @@ use grovedb::{batch::GroveDbOp, Element}; use crate::drive::flags::StorageFlags; use crate::error::drive::DriveError; use crate::error::Error; -use crate::fee::default_costs::{ - STORAGE_DISK_USAGE_CREDIT_PER_BYTE, STORAGE_LOAD_CREDIT_PER_BYTE, - STORAGE_PROCESSING_CREDIT_PER_BYTE, STORAGE_SEEK_COST, +use crate::fee::default_costs::KnownCostItem::{ + StorageDiskUsageCreditPerByte, StorageLoadCreditPerByte, StorageProcessingCreditPerByte, + StorageSeekCost, }; use crate::fee::op::DriveOperation::{ CalculatedCostOperation, FunctionOperation, GroveOperation, PreCalculatedFeeResult, @@ -406,21 +406,23 @@ impl DriveCost for OperationCost { storage_loaded_bytes, hash_node_calls, } = self; + let epoch_cost_for_processing_credit_per_byte = + epoch.cost_for_known_cost_item(StorageProcessingCreditPerByte); let seek_cost = (*seek_count as u64) - .checked_mul(STORAGE_SEEK_COST) + .checked_mul(epoch.cost_for_known_cost_item(StorageSeekCost)) .ok_or_else(|| get_overflow_error("seek cost overflow"))?; let storage_added_bytes_ephemeral_cost = (storage_cost.added_bytes as u64) - .checked_mul(STORAGE_PROCESSING_CREDIT_PER_BYTE) + .checked_mul(epoch_cost_for_processing_credit_per_byte) .ok_or_else(|| get_overflow_error("storage written bytes cost overflow"))?; let storage_replaced_bytes_ephemeral_cost = (storage_cost.replaced_bytes as u64) - .checked_mul(STORAGE_PROCESSING_CREDIT_PER_BYTE) + .checked_mul(epoch_cost_for_processing_credit_per_byte) .ok_or_else(|| get_overflow_error("storage written bytes cost overflow"))?; let storage_removed_bytes_ephemeral_cost = (storage_cost.removed_bytes.total_removed_bytes() as u64) - .checked_mul(STORAGE_PROCESSING_CREDIT_PER_BYTE) + .checked_mul(epoch_cost_for_processing_credit_per_byte) .ok_or_else(|| get_overflow_error("storage written bytes cost overflow"))?; let storage_loaded_bytes_cost = (*storage_loaded_bytes as u64) - .checked_mul(STORAGE_LOAD_CREDIT_PER_BYTE) + .checked_mul(epoch.cost_for_known_cost_item(StorageLoadCreditPerByte)) .ok_or_else(|| get_overflow_error("storage loaded cost overflow"))?; // this can't overflow let hash_node_cost = @@ -435,11 +437,11 @@ impl DriveCost for OperationCost { } /// Return the storage cost from the operation - fn storage_cost(&self, _epoch: &Epoch) -> Result { + fn storage_cost(&self, epoch: &Epoch) -> Result { //todo: deal with epochs let OperationCost { storage_cost, .. } = self; (storage_cost.added_bytes as u64) - .checked_mul(STORAGE_DISK_USAGE_CREDIT_PER_BYTE) + .checked_mul(epoch.cost_for_known_cost_item(StorageDiskUsageCreditPerByte)) .ok_or_else(|| get_overflow_error("storage written bytes cost overflow")) } } diff --git a/packages/rs-drive/src/fee/result/mod.rs b/packages/rs-drive/src/fee/result/mod.rs index 5d2e68001f7..9889309dacf 100644 --- a/packages/rs-drive/src/fee/result/mod.rs +++ b/packages/rs-drive/src/fee/result/mod.rs @@ -147,6 +147,15 @@ impl BalanceChangeForIdentity { } impl FeeResult { + /// Convenience method to create a fee result from processing credits + pub fn new_from_processing_fee(credits: Credits) -> Self { + Self { + storage_fee: 0, + processing_fee: credits, + fee_refunds: Default::default(), + removed_bytes_from_system: 0, + } + } /// Convenience method to get total fee pub fn total_base_fee(&self) -> Credits { self.storage_fee + self.processing_fee diff --git a/packages/rs-drive/src/fee/result/refunds.rs b/packages/rs-drive/src/fee/result/refunds.rs index 460870da18e..c9f336da111 100644 --- a/packages/rs-drive/src/fee/result/refunds.rs +++ b/packages/rs-drive/src/fee/result/refunds.rs @@ -40,10 +40,11 @@ const MIN_REFUND_LIMIT_BYTES: u32 = 32; use crate::error::fee::FeeError; use crate::error::Error; use crate::fee::credits::Credits; -use crate::fee::default_costs::STORAGE_DISK_USAGE_CREDIT_PER_BYTE; +use crate::fee::default_costs::KnownCostItem::StorageDiskUsageCreditPerByte; use crate::fee::epoch::distribution::calculate_storage_fee_refund_amount_and_leftovers; use crate::fee::epoch::{CreditsPerEpoch, EpochIndex}; use crate::fee::get_overflow_error; +use crate::fee_pools::epochs::Epoch; use bincode::Options; use costs::storage_cost::removal::{Identifier, StorageRemovalPerEpochByIdentifier}; use serde::{Deserialize, Serialize}; @@ -75,7 +76,7 @@ impl FeeRefunds { // TODO We should use multipliers let credits: Credits = (bytes as Credits) - .checked_mul(STORAGE_DISK_USAGE_CREDIT_PER_BYTE) + .checked_mul(Epoch::new(current_epoch_index).cost_for_known_cost_item(StorageDiskUsageCreditPerByte)) .ok_or_else(|| { get_overflow_error("storage written bytes cost overflow") })?;