diff --git a/packages/rs-dpp/src/data_contract/accessors/mod.rs b/packages/rs-dpp/src/data_contract/accessors/mod.rs index 4d320e7a001..4840054ef76 100644 --- a/packages/rs-dpp/src/data_contract/accessors/mod.rs +++ b/packages/rs-dpp/src/data_contract/accessors/mod.rs @@ -1,7 +1,9 @@ use crate::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; use crate::data_contract::config::DataContractConfig; use crate::data_contract::document_type::{DocumentType, DocumentTypeRef}; -use crate::data_contract::{DocumentName, TokenContractPosition, EMPTY_GROUPS, EMPTY_TOKENS}; +use crate::data_contract::{ + DocumentName, GroupContractPosition, TokenContractPosition, EMPTY_GROUPS, EMPTY_TOKENS, +}; use crate::metadata::Metadata; use crate::prelude::DataContract; @@ -10,7 +12,7 @@ use platform_value::Identifier; use crate::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::errors::DataContractError; -use crate::data_contract::group::{Group, GroupName}; +use crate::data_contract::group::Group; use std::collections::BTreeMap; pub mod v0; @@ -187,7 +189,7 @@ impl DataContractV0Setters for DataContract { /// Implementing DataContractV1Getters for DataContract impl DataContractV1Getters for DataContract { /// Returns a reference to the groups map. - fn groups(&self) -> &BTreeMap { + fn groups(&self) -> &BTreeMap { match self { DataContract::V0(_) => &EMPTY_GROUPS, DataContract::V1(v1) => &v1.groups, @@ -196,7 +198,7 @@ impl DataContractV1Getters for DataContract { /// Returns a mutable reference to the groups map. /// Returns `None` for V0 since it doesn't have groups. - fn groups_mut(&mut self) -> Option<&mut BTreeMap> { + fn groups_mut(&mut self) -> Option<&mut BTreeMap> { match self { DataContract::V0(_) => None, DataContract::V1(v1) => Some(&mut v1.groups), @@ -230,7 +232,7 @@ impl DataContractV1Getters for DataContract { impl DataContractV1Setters for DataContract { /// Sets the groups map for the data contract. - fn set_groups(&mut self, groups: BTreeMap) { + fn set_groups(&mut self, groups: BTreeMap) { match self { DataContract::V0(_) => {} DataContract::V1(v1) => { @@ -250,11 +252,11 @@ impl DataContractV1Setters for DataContract { } /// Adds or updates a single group in the groups map. - fn add_group(&mut self, name: GroupName, group: Group) { + fn add_group(&mut self, position: GroupContractPosition, group: Group) { match self { DataContract::V0(_) => {} DataContract::V1(v1) => { - v1.groups.insert(name, group); + v1.groups.insert(position, group); } } } diff --git a/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs b/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs index 78a0df7a9b7..489d45b5f18 100644 --- a/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs +++ b/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs @@ -1,16 +1,16 @@ use crate::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; -use crate::data_contract::group::{Group, GroupName}; -use crate::data_contract::TokenContractPosition; +use crate::data_contract::group::Group; +use crate::data_contract::{GroupContractPosition, TokenContractPosition}; use platform_value::Identifier; use std::collections::BTreeMap; pub trait DataContractV1Getters: DataContractV0Getters { /// Returns a reference to the groups map. - fn groups(&self) -> &BTreeMap; + fn groups(&self) -> &BTreeMap; /// Returns a mutable reference to the groups map. - fn groups_mut(&mut self) -> Option<&mut BTreeMap>; + fn groups_mut(&mut self) -> Option<&mut BTreeMap>; /// Returns a reference to the tokens map. fn tokens(&self) -> &BTreeMap; @@ -24,13 +24,13 @@ pub trait DataContractV1Getters: DataContractV0Getters { pub trait DataContractV1Setters: DataContractV0Setters { /// Sets the groups map for the data contract. - fn set_groups(&mut self, groups: BTreeMap); + fn set_groups(&mut self, groups: BTreeMap); /// Sets the tokens map for the data contract. fn set_tokens(&mut self, tokens: BTreeMap); /// Adds or updates a single group in the groups map. - fn add_group(&mut self, name: GroupName, group: Group); + fn add_group(&mut self, pos: GroupContractPosition, group: Group); /// Adds or updates a single token configuration in the tokens map. fn add_token(&mut self, pos: TokenContractPosition, token: TokenConfiguration); diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs index a08b4590185..ff06d882bd5 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs @@ -1,5 +1,4 @@ use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationConventionV0; -use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::ChangeControlRules; use crate::data_contract::group::RequiredSigners; diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs index fa82163d4cc..e5e34c66646 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs @@ -1,5 +1,5 @@ use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Decode, Encode}; use derive_more::From; use serde::{Deserialize, Serialize}; use std::borrow::Cow; diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs index d6f32abdf25..ad86bc0d76b 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs @@ -4,7 +4,7 @@ use crate::data_contract::change_control_rules::authorized_action_takers::Author use crate::data_contract::change_control_rules::v0::ChangeControlRulesV0; use crate::data_contract::change_control_rules::ChangeControlRules; use crate::data_contract::group::RequiredSigners; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Decode, Encode}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; diff --git a/packages/rs-dpp/src/data_contract/change_control_rules/authorized_action_takers.rs b/packages/rs-dpp/src/data_contract/change_control_rules/authorized_action_takers.rs index e099c8cbd9b..e669504cda4 100644 --- a/packages/rs-dpp/src/data_contract/change_control_rules/authorized_action_takers.rs +++ b/packages/rs-dpp/src/data_contract/change_control_rules/authorized_action_takers.rs @@ -1,7 +1,7 @@ use crate::data_contract::group::accessors::v0::GroupV0Getters; use crate::data_contract::group::{Group, GroupMemberPower}; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::multi_identity_events::ActionTaker; +use bincode::{Decode, Encode}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; diff --git a/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs b/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs index 81194382f46..e875a6fe2c4 100644 --- a/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs @@ -1,8 +1,8 @@ use crate::consensus::basic::data_contract::UnknownDocumentCreationRestrictionModeError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::ProtocolError; +use bincode::{Decode, Encode}; use std::fmt; use std::fmt::{Display, Formatter}; diff --git a/packages/rs-dpp/src/data_contract/group/mod.rs b/packages/rs-dpp/src/data_contract/group/mod.rs index c1762fad525..df3427ede35 100644 --- a/packages/rs-dpp/src/data_contract/group/mod.rs +++ b/packages/rs-dpp/src/data_contract/group/mod.rs @@ -1,19 +1,31 @@ use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; use crate::data_contract::group::v0::GroupV0; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; pub mod accessors; mod v0; - -pub type GroupName = String; pub type RequiredSigners = u8; pub type GroupMemberPower = u32; pub type GroupRequiredPower = u32; -#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq)] +#[derive( + Serialize, + Deserialize, + Decode, + Encode, + PlatformSerialize, + PlatformDeserialize, + Debug, + Clone, + PartialEq, + Eq, +)] +#[platform_serialize(unversioned)] pub enum Group { V0(GroupV0), } diff --git a/packages/rs-dpp/src/data_contract/group/v0/mod.rs b/packages/rs-dpp/src/data_contract/group/v0/mod.rs index ae8b64532a0..00dbb9bee63 100644 --- a/packages/rs-dpp/src/data_contract/group/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/group/v0/mod.rs @@ -1,11 +1,25 @@ use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; use crate::data_contract::group::{GroupMemberPower, GroupRequiredPower}; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq)] +#[derive( + Serialize, + Deserialize, + Decode, + Encode, + PlatformSerialize, + PlatformDeserialize, + Debug, + Clone, + PartialEq, + Eq, +)] +#[platform_serialize(unversioned)] pub struct GroupV0 { pub members: BTreeMap, pub required_power: GroupRequiredPower, diff --git a/packages/rs-dpp/src/data_contract/mod.rs b/packages/rs-dpp/src/data_contract/mod.rs index b58bd46cce9..0897fd20287 100644 --- a/packages/rs-dpp/src/data_contract/mod.rs +++ b/packages/rs-dpp/src/data_contract/mod.rs @@ -38,7 +38,7 @@ pub mod accessors; pub mod associated_token; pub mod change_control_rules; pub mod config; -mod group; +pub mod group; pub mod storage_requirements; use crate::data_contract::serialized_version::{ @@ -51,7 +51,7 @@ use crate::ProtocolError; use crate::ProtocolError::{PlatformDeserializationError, PlatformSerializationError}; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; -use crate::data_contract::group::{Group, GroupName}; +use crate::data_contract::group::Group; use crate::data_contract::v0::DataContractV0; use crate::data_contract::v1::DataContractV1; use platform_version::TryIntoPlatformVersioned; @@ -62,13 +62,14 @@ type JsonSchema = JsonValue; type DefinitionName = String; pub type DocumentName = String; pub type TokenName = String; +pub type GroupContractPosition = u16; pub type TokenContractPosition = u16; type PropertyPath = String; pub const INITIAL_DATA_CONTRACT_VERSION: u32 = 1; // Define static empty BTreeMaps -static EMPTY_GROUPS: Lazy> = Lazy::new(|| BTreeMap::new()); +static EMPTY_GROUPS: Lazy> = Lazy::new(|| BTreeMap::new()); static EMPTY_TOKENS: Lazy> = Lazy::new(|| BTreeMap::new()); diff --git a/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs b/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs index 03591d44fea..6cd119e3bf0 100644 --- a/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs @@ -5,7 +5,7 @@ use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; use crate::data_contract::v0::DataContractV0; use crate::data_contract::v1::DataContractV1; use crate::data_contract::{DataContract, DefinitionName, DocumentName}; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Decode, Encode}; use platform_value::{Identifier, Value}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs b/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs index de7c8cbac79..176f06f57d1 100644 --- a/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs +++ b/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs @@ -3,11 +3,13 @@ use crate::data_contract::config::DataContractConfig; use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; -use crate::data_contract::group::{Group, GroupName}; +use crate::data_contract::group::Group; use crate::data_contract::v0::DataContractV0; use crate::data_contract::v1::DataContractV1; -use crate::data_contract::{DataContract, DefinitionName, DocumentName, TokenContractPosition}; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use crate::data_contract::{ + DataContract, DefinitionName, DocumentName, GroupContractPosition, TokenContractPosition, +}; +use bincode::{Decode, Encode}; use platform_value::{Identifier, Value}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -35,7 +37,7 @@ pub struct DataContractInSerializationFormatV1 { pub document_schemas: BTreeMap, /// Groups that allow for specific multiparty actions on the contract - pub groups: BTreeMap, + pub groups: BTreeMap, /// The tokens on the contract. pub tokens: BTreeMap, diff --git a/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs b/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs index 07e0e597aa3..2dda757c4da 100644 --- a/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs +++ b/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs @@ -4,13 +4,13 @@ use crate::data_contract::document_type::{DocumentType, DocumentTypeRef}; use crate::data_contract::errors::DataContractError; use crate::data_contract::v1::DataContractV1; -use crate::data_contract::{DocumentName, TokenContractPosition}; +use crate::data_contract::{DocumentName, GroupContractPosition, TokenContractPosition}; use crate::metadata::Metadata; use crate::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; -use crate::data_contract::group::{Group, GroupName}; +use crate::data_contract::group::Group; use crate::util::hash::hash_double; use platform_value::Identifier; use std::collections::BTreeMap; @@ -144,11 +144,11 @@ impl DataContractV0Setters for DataContractV1 { } impl DataContractV1Getters for DataContractV1 { - fn groups(&self) -> &BTreeMap { + fn groups(&self) -> &BTreeMap { &self.groups } - fn groups_mut(&mut self) -> Option<&mut BTreeMap> { + fn groups_mut(&mut self) -> Option<&mut BTreeMap> { Some(&mut self.groups) } @@ -172,7 +172,7 @@ impl DataContractV1Getters for DataContractV1 { } impl DataContractV1Setters for DataContractV1 { - fn set_groups(&mut self, groups: BTreeMap) { + fn set_groups(&mut self, groups: BTreeMap) { self.groups = groups; } @@ -180,8 +180,8 @@ impl DataContractV1Setters for DataContractV1 { self.tokens = tokens; } - fn add_group(&mut self, name: GroupName, group: Group) { - self.groups.insert(name, group); + fn add_group(&mut self, group_position: GroupContractPosition, group: Group) { + self.groups.insert(group_position, group); } fn add_token(&mut self, name: TokenContractPosition, token: TokenConfiguration) { diff --git a/packages/rs-dpp/src/data_contract/v1/data_contract.rs b/packages/rs-dpp/src/data_contract/v1/data_contract.rs index 554d9ba475d..60a6527fd07 100644 --- a/packages/rs-dpp/src/data_contract/v1/data_contract.rs +++ b/packages/rs-dpp/src/data_contract/v1/data_contract.rs @@ -6,8 +6,10 @@ use platform_value::Value; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::config::DataContractConfig; use crate::data_contract::document_type::DocumentType; -use crate::data_contract::group::{Group, GroupName}; -use crate::data_contract::{DefinitionName, DocumentName, TokenContractPosition}; +use crate::data_contract::group::Group; +use crate::data_contract::{ + DefinitionName, DocumentName, GroupContractPosition, TokenContractPosition, +}; use crate::metadata::Metadata; /// `DataContractV1` represents a data contract in a decentralized platform. @@ -24,7 +26,7 @@ use crate::metadata::Metadata; /// In `DataContractV1`, two significant features were introduced to enhance contract governance /// and support token-related operations: /// -/// 1. **Groups** (`groups: BTreeMap`) +/// 1. **Groups** (`groups: BTreeMap`) /// - Groups allow for specific multiparty actions on the contract. Each group is defined with a /// set of members (`Identifier`) and their corresponding member power (`u32`). /// - Groups facilitate fine-grained access control and decision-making processes by enabling @@ -66,7 +68,7 @@ pub struct DataContractV1 { pub schema_defs: Option>, /// Groups that allow for specific multiparty actions on the contract - pub groups: BTreeMap, + pub groups: BTreeMap, /// The tokens on the contract. pub tokens: BTreeMap, diff --git a/packages/rs-dpp/src/document/generate_document_id.rs b/packages/rs-dpp/src/document/generate_document_id.rs index 96d4af68c17..b14fc599a44 100644 --- a/packages/rs-dpp/src/document/generate_document_id.rs +++ b/packages/rs-dpp/src/document/generate_document_id.rs @@ -1,5 +1,4 @@ use crate::document::Document; -use crate::prelude::IdentityNonce; use crate::{prelude::Identifier, util::hash::hash_double_to_vec}; impl Document { diff --git a/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs b/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs index a753c9ccd62..e43de444588 100644 --- a/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs @@ -4,7 +4,7 @@ use crate::consensus::state::data_trigger::data_trigger_invalid_result_error::Da use crate::consensus::state::state_error::StateError; use crate::consensus::ConsensusError; use crate::errors::ProtocolError; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use thiserror::Error; diff --git a/packages/rs-dpp/src/group/action_event.rs b/packages/rs-dpp/src/group/action_event.rs new file mode 100644 index 00000000000..54cb5a950f5 --- /dev/null +++ b/packages/rs-dpp/src/group/action_event.rs @@ -0,0 +1,12 @@ +use crate::tokens::token_event::TokenEvent; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum GroupActionEvent { + TokenEvent(TokenEvent), +} diff --git a/packages/rs-dpp/src/group/group_action/mod.rs b/packages/rs-dpp/src/group/group_action/mod.rs new file mode 100644 index 00000000000..5f6ac854939 --- /dev/null +++ b/packages/rs-dpp/src/group/group_action/mod.rs @@ -0,0 +1,14 @@ +mod v0; + +use crate::group::group_action::v0::GroupActionV0; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum GroupAction { + V0(GroupActionV0), +} diff --git a/packages/rs-dpp/src/group/group_action/v0/mod.rs b/packages/rs-dpp/src/group/group_action/v0/mod.rs new file mode 100644 index 00000000000..5f90ce0788b --- /dev/null +++ b/packages/rs-dpp/src/group/group_action/v0/mod.rs @@ -0,0 +1,12 @@ +use crate::group::action_event::GroupActionEvent; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub struct GroupActionV0 { + pub event: GroupActionEvent, +} diff --git a/packages/rs-dpp/src/group/mod.rs b/packages/rs-dpp/src/group/mod.rs new file mode 100644 index 00000000000..42dda497ca1 --- /dev/null +++ b/packages/rs-dpp/src/group/mod.rs @@ -0,0 +1,29 @@ +use crate::data_contract::GroupContractPosition; +use bincode::{Decode, Encode}; +use derive_more::Display; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +pub mod action_event; +pub mod group_action; + +#[derive(Debug, Clone, Encode, Decode, Default, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display("ID: {}, Action ID: {}", "id", "action_id")] +pub struct GroupStateTransitionInfo { + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$groupContractPosition") + )] + pub group_contract_position: GroupContractPosition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$groupActionId") + )] + pub action_id: Identifier, +} diff --git a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs index 0a7b020cc1a..6829ea6eaf3 100644 --- a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs +++ b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs @@ -4,7 +4,6 @@ use std::convert::TryFrom; use crate::util::hash::hash_double; use crate::{identifier::Identifier, ProtocolError}; -pub use bincode::{Decode, Encode}; use dashcore::OutPoint; /// Instant Asset Lock Proof is a part of Identity Create and Identity Topup diff --git a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs index 2e97ad74808..a25ded9547e 100644 --- a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs +++ b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs @@ -4,7 +4,7 @@ use dashcore::{OutPoint, Transaction}; use serde::{Deserialize, Deserializer, Serialize}; -pub use bincode::{Decode, Encode}; +use bincode::{Decode, Encode}; pub use instant::*; use platform_value::Value; diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index de0c10f6c47..e1dd2787b1d 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -60,6 +60,7 @@ pub mod voting; #[cfg(feature = "core-types")] pub mod core_types; +pub mod group; pub mod withdrawal; pub use async_trait; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs index eae1a4790f8..910c0795ce9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs @@ -3,9 +3,9 @@ use std::collections::BTreeMap; use derive_more::{Display, From}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Encode, Decode}; use crate::prelude::{IdentityNonce, Revision}; -use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenIssuanceTransition, TokenTransferTransition}; +use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenMintTransition, TokenTransferTransition}; use crate::state_transition::batch_transition::batched_transition::{DocumentPurchaseTransition, DocumentTransferTransition, DocumentUpdatePriceTransition}; use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; @@ -86,7 +86,7 @@ impl BatchTransitionResolversV0 for DocumentTransition { None } - fn as_transition_token_issuance(&self) -> Option<&TokenIssuanceTransition> { + fn as_transition_token_issuance(&self) -> Option<&TokenMintTransition> { None } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs index f4ff1666aff..8cfa58e7e37 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs @@ -12,6 +12,7 @@ pub mod document_transfer_transition; pub mod document_transition; pub mod document_transition_action_type; pub mod document_update_price_transition; +pub mod multi_party_action; mod resolvers; pub mod token_base_transition; pub mod token_burn_transition; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs new file mode 100644 index 00000000000..9b648ea5f90 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs @@ -0,0 +1,5 @@ +use platform_value::Identifier; + +pub trait AllowedAsMultiPartyAction { + fn action_id(&self, owner_id: Identifier) -> Identifier; +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs index fde56d9f9e9..22fdba19a57 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs @@ -4,7 +4,7 @@ use crate::state_transition::batch_transition::batched_transition::{ use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; use crate::state_transition::batch_transition::{ DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, - TokenBurnTransition, TokenIssuanceTransition, TokenTransferTransition, + TokenBurnTransition, TokenMintTransition, TokenTransferTransition, }; impl BatchTransitionResolversV0 for BatchedTransition { @@ -50,7 +50,7 @@ impl BatchTransitionResolversV0 for BatchedTransition { } } - fn as_transition_token_issuance(&self) -> Option<&TokenIssuanceTransition> { + fn as_transition_token_issuance(&self) -> Option<&TokenMintTransition> { match self { BatchedTransition::Document(_) => None, BatchedTransition::Token(token) => token.as_transition_token_issuance(), @@ -108,7 +108,7 @@ impl<'a> BatchTransitionResolversV0 for BatchedTransitionRef<'a> { } } - fn as_transition_token_issuance(&self) -> Option<&TokenIssuanceTransition> { + fn as_transition_token_issuance(&self) -> Option<&TokenMintTransition> { match self { BatchedTransitionRef::Document(_) => None, BatchedTransitionRef::Token(token) => token.as_transition_token_issuance(), diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs index 2863c1718d9..98529f9e9e5 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs @@ -2,6 +2,8 @@ pub(in crate::state_transition::state_transitions::document::batch_transition) m pub const DATA_CONTRACT_ID: &str = "$dataContractId"; pub const TOKEN_CONTRACT_POSITION: &str = "$tokenContractPosition"; pub const TOKEN_ID: &str = "$tokenId"; + pub const GROUP_CONTRACT_POSITION: &str = "$groupContractPosition"; + pub const GROUP_ACTION_ID: &str = "$groupActionId"; pub const ACTION: &str = "$action"; pub const IDENTITY_CONTRACT_NONCE: &str = "$identityContractNonce"; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs index 7a695e5040d..e685bccdbee 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs @@ -15,10 +15,15 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "state-transition-value-conversion")] use crate::data_contract::accessors::v0::DataContractV0Getters; +#[cfg(feature = "state-transition-value-conversion")] +use crate::data_contract::accessors::v1::DataContractV1Getters; +use crate::group::GroupStateTransitionInfo; use crate::identifier::Identifier; use crate::prelude::IdentityNonce; #[cfg(feature = "state-transition-value-conversion")] use crate::state_transition::batch_transition::token_base_transition::property_names; +#[cfg(feature = "state-transition-value-conversion")] +use crate::tokens::errors::TokenError; #[cfg(any( feature = "state-transition-json-conversion", feature = "state-transition-value-conversion" @@ -61,6 +66,9 @@ pub struct TokenBaseTransitionV0 { serde(rename = "$tokenId") )] pub token_id: Identifier, + /// Using group multi party rules for authentication + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub using_group: Option, } impl TokenBaseTransitionV0 { @@ -70,21 +78,37 @@ impl TokenBaseTransitionV0 { data_contract: DataContract, identity_contract_nonce: IdentityNonce, ) -> Result { + let token_contract_position = map + .remove_integer(property_names::TOKEN_CONTRACT_POSITION) + .map_err(ProtocolError::ValueError)?; Ok(TokenBaseTransitionV0 { identity_contract_nonce, - token_contract_position: map - .remove_integer(property_names::TOKEN_CONTRACT_POSITION) - .map_err(ProtocolError::ValueError)?, + token_contract_position, data_contract_id: Identifier::new( map.remove_optional_hash256_bytes(property_names::DATA_CONTRACT_ID) .map_err(ProtocolError::ValueError)? .unwrap_or(data_contract.id().to_buffer()), ), - token_id: Identifier::new( - map.remove_optional_hash256_bytes(property_names::TOKEN_ID) - .map_err(ProtocolError::ValueError)? - .unwrap_or(data_contract.id().to_buffer()), - ), + token_id: map + .remove_optional_hash256_bytes(property_names::TOKEN_ID) + .map_err(ProtocolError::ValueError)? + .map(Identifier::new) + .unwrap_or(data_contract.token_id(token_contract_position).ok_or( + ProtocolError::Token(TokenError::TokenNotFoundAtPositionError.into()), + )?), + using_group: map + .remove_optional_integer(property_names::GROUP_CONTRACT_POSITION) + .map_err(ProtocolError::ValueError)? + .map(|group_contract_position| { + Ok::(GroupStateTransitionInfo { + group_contract_position, + action_id: map + .remove_hash256_bytes(property_names::GROUP_ACTION_ID) + .map_err(ProtocolError::ValueError)? + .into(), + }) + }) + .transpose()?, }) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs index 70297bddb50..9e0802ca875 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs @@ -1,3 +1,5 @@ +use crate::data_contract::GroupContractPosition; +use crate::group::GroupStateTransitionInfo; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; use platform_value::Identifier; @@ -20,6 +22,11 @@ pub trait TokenBaseTransitionV0Methods { fn set_token_id(&mut self, token_id: Identifier); + /// Returns the group ID. + fn group_position(&self) -> Option; + + fn set_group_info(&mut self, group_info: Option); + /// Sets the data contract ID. fn set_data_contract_id(&mut self, data_contract_id: Identifier); fn identity_contract_nonce(&self) -> IdentityNonce; @@ -66,4 +73,14 @@ impl TokenBaseTransitionV0Methods for TokenBaseTransitionV0 { fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { self.identity_contract_nonce = identity_contract_nonce; } + + fn group_position(&self) -> Option { + self.using_group + .as_ref() + .map(|info| info.group_contract_position) + } + + fn set_group_info(&mut self, group_info: Option) { + self.using_group = group_info; + } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs index 53a3244db1d..2bc0f33dfcd 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs @@ -1,3 +1,5 @@ +use crate::data_contract::GroupContractPosition; +use crate::group::GroupStateTransitionInfo; use crate::prelude::IdentityNonce; use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; @@ -34,15 +36,27 @@ impl TokenBaseTransitionV0Methods for TokenBaseTransition { } } + fn token_id_ref(&self) -> &Identifier { + match self { + TokenBaseTransition::V0(v0) => v0.token_id_ref(), + } + } + fn set_token_id(&mut self, token_id: Identifier) { match self { TokenBaseTransition::V0(v0) => v0.set_token_id(token_id), } } - fn token_id_ref(&self) -> &Identifier { + fn group_position(&self) -> Option { match self { - TokenBaseTransition::V0(v0) => v0.token_id_ref(), + TokenBaseTransition::V0(v0) => v0.group_position(), + } + } + + fn set_group_info(&mut self, group_info: Option) { + match self { + TokenBaseTransition::V0(v0) => v0.set_group_info(group_info), } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs index dcf6d104a22..1da7aea51b3 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs @@ -1,6 +1,10 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use crate::state_transition::batch_transition::token_burn_transition::TokenBurnTransitionV0; +use crate::util::hash::hash_double; impl TokenBaseTransitionAccessors for TokenBurnTransitionV0 { fn base(&self) -> &TokenBaseTransition { @@ -16,7 +20,9 @@ impl TokenBaseTransitionAccessors for TokenBurnTransitionV0 { } } -pub trait TokenBurnTransitionV0Methods: TokenBaseTransitionAccessors { +pub trait TokenBurnTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ fn burn_amount(&self) -> u64; fn set_burn_amount(&mut self, amount: u64); @@ -52,3 +58,19 @@ impl TokenBurnTransitionV0Methods for TokenBurnTransitionV0 { self.public_note = public_note; } } + +impl AllowedAsMultiPartyAction for TokenBurnTransitionV0 { + fn action_id(&self, owner_id: Identifier) -> Identifier { + let TokenBurnTransitionV0 { + base, burn_amount, .. + } = self; + + let mut bytes = b"action_burn".to_vec(); + bytes.extend_from_slice(base.token_id().as_bytes()); + bytes.extend_from_slice(owner_id.as_bytes()); + bytes.extend_from_slice(&base.identity_contract_nonce().to_be_bytes()); + bytes.extend_from_slice(&burn_amount.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs index 4c83f78232f..96b4b5ee969 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs @@ -1,3 +1,5 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; use crate::state_transition::batch_transition::token_burn_transition::TokenBurnTransition; @@ -54,3 +56,11 @@ impl TokenBurnTransitionV0Methods for TokenBurnTransition { } } } + +impl AllowedAsMultiPartyAction for TokenBurnTransition { + fn action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenBurnTransition::V0(v0) => v0.action_id(owner_id), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/mod.rs index a82e5a3a6fe..a37fe199c3a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/mod.rs @@ -5,20 +5,20 @@ use bincode::{Decode, Encode}; use derive_more::{Display, From}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; -pub use v0::TokenIssuanceTransitionV0; +pub use v0::TokenMintTransitionV0; #[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] #[cfg_attr( feature = "state-transition-serde-conversion", derive(Serialize, Deserialize) )] -pub enum TokenIssuanceTransition { +pub enum TokenMintTransition { #[display("V0({})", "_0")] - V0(TokenIssuanceTransitionV0), + V0(TokenMintTransitionV0), } -impl Default for TokenIssuanceTransition { +impl Default for TokenMintTransition { fn default() -> Self { - TokenIssuanceTransition::V0(TokenIssuanceTransitionV0::default()) // since only v0 + TokenMintTransition::V0(TokenMintTransitionV0::default()) // since only v0 } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/mod.rs index 2e4d17a6ebf..412111a65c7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/mod.rs @@ -20,7 +20,7 @@ pub use super::super::document_base_transition::IDENTIFIER_FIELDS; derive(Serialize, Deserialize), serde(rename_all = "camelCase") )] -pub struct TokenIssuanceTransitionV0 { +pub struct TokenMintTransitionV0 { /// Document Base Transition #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] pub base: TokenBaseTransition, @@ -42,7 +42,7 @@ pub struct TokenIssuanceTransitionV0 { pub public_note: Option, } -impl fmt::Display for TokenIssuanceTransitionV0 { +impl fmt::Display for TokenMintTransitionV0 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Format the base transition (assuming `TokenBaseTransition` implements Display) write!( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/v0_methods.rs index 5f24acc145b..9aa6948dfd2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0/v0_methods.rs @@ -1,9 +1,12 @@ use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; -use crate::state_transition::batch_transition::token_issuance_transition::TokenIssuanceTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_issuance_transition::TokenMintTransitionV0; +use crate::util::hash::hash_double; -impl TokenBaseTransitionAccessors for TokenIssuanceTransitionV0 { +impl TokenBaseTransitionAccessors for TokenMintTransitionV0 { fn base(&self) -> &TokenBaseTransition { &self.base } @@ -17,7 +20,9 @@ impl TokenBaseTransitionAccessors for TokenIssuanceTransitionV0 { } } -pub trait TokenIssuanceTransitionV0Methods: TokenBaseTransitionAccessors { +pub trait TokenMintTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ fn amount(&self) -> u64; fn set_amount(&mut self, amount: u64); @@ -38,7 +43,7 @@ pub trait TokenIssuanceTransitionV0Methods: TokenBaseTransitionAccessors { fn set_issued_to_identity_id(&mut self, issued_to_identity_id: Option); } -impl TokenIssuanceTransitionV0Methods for TokenIssuanceTransitionV0 { +impl TokenMintTransitionV0Methods for TokenMintTransitionV0 { fn amount(&self) -> u64 { self.amount } @@ -66,3 +71,17 @@ impl TokenIssuanceTransitionV0Methods for TokenIssuanceTransitionV0 { self.issued_to_identity_id = issued_to_identity_id; } } + +impl AllowedAsMultiPartyAction for TokenMintTransitionV0 { + fn action_id(&self, owner_id: Identifier) -> Identifier { + let TokenMintTransitionV0 { base, amount, .. } = self; + + let mut bytes = b"action_mint".to_vec(); + bytes.extend_from_slice(base.token_id().as_bytes()); + bytes.extend_from_slice(owner_id.as_bytes()); + bytes.extend_from_slice(&base.identity_contract_nonce().to_be_bytes()); + bytes.extend_from_slice(&amount.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0_methods.rs index 71b228a35ae..78726f5976d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_issuance_transition/v0_methods.rs @@ -1,69 +1,78 @@ use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; -use crate::state_transition::batch_transition::token_issuance_transition::TokenIssuanceTransition; -use crate::state_transition::batch_transition::token_issuance_transition::v0::v0_methods::TokenIssuanceTransitionV0Methods; +use crate::state_transition::batch_transition::token_issuance_transition::TokenMintTransition; +use crate::state_transition::batch_transition::token_issuance_transition::v0::v0_methods::TokenMintTransitionV0Methods; -impl TokenBaseTransitionAccessors for TokenIssuanceTransition { +impl TokenBaseTransitionAccessors for TokenMintTransition { fn base(&self) -> &TokenBaseTransition { match self { - TokenIssuanceTransition::V0(v0) => &v0.base, + TokenMintTransition::V0(v0) => &v0.base, } } fn base_mut(&mut self) -> &mut TokenBaseTransition { match self { - TokenIssuanceTransition::V0(v0) => &mut v0.base, + TokenMintTransition::V0(v0) => &mut v0.base, } } fn set_base(&mut self, base: TokenBaseTransition) { match self { - TokenIssuanceTransition::V0(v0) => v0.base = base, + TokenMintTransition::V0(v0) => v0.base = base, } } } -impl TokenIssuanceTransitionV0Methods for TokenIssuanceTransition { +impl TokenMintTransitionV0Methods for TokenMintTransition { fn amount(&self) -> u64 { match self { - TokenIssuanceTransition::V0(v0) => v0.amount(), + TokenMintTransition::V0(v0) => v0.amount(), } } fn set_amount(&mut self, amount: u64) { match self { - TokenIssuanceTransition::V0(v0) => v0.set_amount(amount), + TokenMintTransition::V0(v0) => v0.set_amount(amount), } } fn public_note(&self) -> Option<&String> { match self { - TokenIssuanceTransition::V0(v0) => v0.public_note(), + TokenMintTransition::V0(v0) => v0.public_note(), } } fn public_note_owned(self) -> Option { match self { - TokenIssuanceTransition::V0(v0) => v0.public_note_owned(), + TokenMintTransition::V0(v0) => v0.public_note_owned(), } } fn set_public_note(&mut self, public_note: Option) { match self { - TokenIssuanceTransition::V0(v0) => v0.set_public_note(public_note), + TokenMintTransition::V0(v0) => v0.set_public_note(public_note), } } fn issued_to_identity_id(&self) -> Option { match self { - TokenIssuanceTransition::V0(v0) => v0.issued_to_identity_id(), + TokenMintTransition::V0(v0) => v0.issued_to_identity_id(), } } fn set_issued_to_identity_id(&mut self, issued_to_identity_id: Option) { match self { - TokenIssuanceTransition::V0(v0) => v0.set_issued_to_identity_id(issued_to_identity_id), + TokenMintTransition::V0(v0) => v0.set_issued_to_identity_id(issued_to_identity_id), + } + } +} + +impl AllowedAsMultiPartyAction for TokenMintTransition { + fn action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenMintTransition::V0(v0) => v0.action_id(owner_id), } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs index 5a143fcd62b..5527b77e557 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs @@ -2,9 +2,9 @@ use derive_more::{Display, From}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; use platform_value::Identifier; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Encode, Decode}; use crate::prelude::IdentityNonce; -use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenIssuanceTransition, TokenTransferTransition}; +use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenMintTransition, TokenTransferTransition}; use crate::state_transition::batch_transition::batched_transition::{DocumentPurchaseTransition, DocumentTransferTransition}; use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; @@ -21,7 +21,7 @@ pub enum TokenTransition { Burn(TokenBurnTransition), #[display("TokenIssuanceTransition({})", "_0")] - Mint(TokenIssuanceTransition), + Mint(TokenMintTransition), #[display("TokenTransferTransition({})", "_0")] Transfer(TokenTransferTransition), @@ -54,7 +54,7 @@ impl BatchTransitionResolversV0 for TokenTransition { None } } - fn as_transition_token_issuance(&self) -> Option<&TokenIssuanceTransition> { + fn as_transition_token_issuance(&self) -> Option<&TokenMintTransition> { if let Self::Mint(ref t) = self { Some(t) } else { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/mod.rs index 0ded71c1f97..11fc10aa5d2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/mod.rs @@ -17,7 +17,7 @@ pub use self::batched_transition::{ document_delete_transition::DocumentDeleteTransition, document_replace_transition, document_replace_transition::DocumentReplaceTransition, token_base_transition, token_burn_transition, token_burn_transition::TokenBurnTransition, token_issuance_transition, - token_issuance_transition::TokenIssuanceTransition, token_transfer_transition, + token_issuance_transition::TokenMintTransition, token_transfer_transition, token_transfer_transition::TokenTransferTransition, }; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs index e1cf7a939c9..66f862789d2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs @@ -3,7 +3,7 @@ use crate::state_transition::batch_transition::batched_transition::{ }; use crate::state_transition::batch_transition::{ DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, - TokenBurnTransition, TokenIssuanceTransition, TokenTransferTransition, + TokenBurnTransition, TokenMintTransition, TokenTransferTransition, }; pub trait BatchTransitionResolversV0 { @@ -13,6 +13,6 @@ pub trait BatchTransitionResolversV0 { fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition>; fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition>; fn as_transition_token_burn(&self) -> Option<&TokenBurnTransition>; - fn as_transition_token_issuance(&self) -> Option<&TokenIssuanceTransition>; + fn as_transition_token_issuance(&self) -> Option<&TokenMintTransition>; fn as_transition_token_transfer(&self) -> Option<&TokenTransferTransition>; } diff --git a/packages/rs-dpp/src/tokens/errors.rs b/packages/rs-dpp/src/tokens/errors.rs index 4a0fa2eb39b..823e1f577c2 100644 --- a/packages/rs-dpp/src/tokens/errors.rs +++ b/packages/rs-dpp/src/tokens/errors.rs @@ -4,4 +4,6 @@ use thiserror::Error; pub enum TokenError { #[error("There is no destination identity to put the token balance to")] DestinationIdentityForMintingNotSetError, + #[error("There is no token at this position")] + TokenNotFoundAtPositionError, } diff --git a/packages/rs-dpp/src/tokens/token_event.rs b/packages/rs-dpp/src/tokens/token_event.rs index 8a3d3a6c0ff..c79056872b2 100644 --- a/packages/rs-dpp/src/tokens/token_event.rs +++ b/packages/rs-dpp/src/tokens/token_event.rs @@ -2,6 +2,8 @@ use crate::balances::credits::TokenAmount; use crate::prelude::{ DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex, }; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; pub type TokenEventPublicNote = Option; @@ -11,8 +13,12 @@ pub type TokenEventPersonalEncryptedNote = Option<( DerivationEncryptionKeyIndex, Vec, )>; +use crate::ProtocolError; -#[derive(Debug, PartialEq, PartialOrd, Clone, Eq)] +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version pub enum TokenEvent { Mint(TokenAmount, TokenEventPublicNote), Burn(TokenAmount, TokenEventPublicNote), diff --git a/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs b/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs index 7ff0929f612..ed4c0fc0797 100644 --- a/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs +++ b/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs @@ -1,8 +1,8 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0; use crate::document::Document; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_value::Identifier; use platform_version::version::PlatformVersion; diff --git a/packages/rs-dpp/src/voting/contender_structs/mod.rs b/packages/rs-dpp/src/voting/contender_structs/mod.rs index 0e8d96c25fe..a71c77f19ab 100644 --- a/packages/rs-dpp/src/voting/contender_structs/mod.rs +++ b/packages/rs-dpp/src/voting/contender_structs/mod.rs @@ -3,9 +3,9 @@ mod contender; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0; use crate::document::Document; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_value::Identifier; use platform_version::version::PlatformVersion; use std::fmt; diff --git a/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs b/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs index 12eb2b400cc..90a920fa78e 100644 --- a/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs +++ b/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs @@ -1,13 +1,13 @@ mod v0; use crate::block::block_info::BlockInfo; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::contender_structs::{ ContenderWithSerializedDocument, FinalizedResourceVoteChoicesWithVoterInfo, }; use crate::voting::vote_info_storage::contested_document_vote_poll_stored_info::v0::ContestedDocumentVotePollStoredInfoV0; use crate::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo; use crate::ProtocolError; +use bincode::{Decode, Encode}; use derive_more::From; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; diff --git a/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs b/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs index 21f953f844c..9342eae819a 100644 --- a/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs +++ b/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs @@ -1,7 +1,7 @@ -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::serialization::PlatformSerializable; use crate::util::hash::hash_double; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::{Identifier, Value}; #[cfg(feature = "vote-serde-conversion")] diff --git a/packages/rs-dpp/src/voting/vote_polls/mod.rs b/packages/rs-dpp/src/voting/vote_polls/mod.rs index 9186451e680..938a852ed4e 100644 --- a/packages/rs-dpp/src/voting/vote_polls/mod.rs +++ b/packages/rs-dpp/src/voting/vote_polls/mod.rs @@ -1,6 +1,6 @@ -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; use crate::ProtocolError; +use bincode::{Decode, Encode}; use derive_more::From; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; diff --git a/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs b/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs index 8ee89fe3714..15787e88d73 100644 --- a/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs +++ b/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs @@ -1,6 +1,6 @@ -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::votes::resource_vote::v0::ResourceVoteV0; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; #[cfg(feature = "vote-serde-conversion")] use serde::{Deserialize, Serialize}; diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs index 46a0590c01c..b3d9eae7f67 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs @@ -17,7 +17,9 @@ use drive::drive::identity::withdrawals::paths::{ WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, }; use drive::drive::system::misc_path; +use drive::drive::RootTree; use drive::grovedb::{Element, Transaction}; +use drive::grovedb_path::SubtreePath; impl Platform { /// Executes protocol-specific events on the first block after a protocol version change. @@ -102,6 +104,15 @@ impl Platform { transaction: &Transaction, platform_version: &PlatformVersion, ) -> Result<(), Error> { + self.drive.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::GroupActions as u8], + Some(transaction), + None, + &mut vec![], + &platform_version.drive, + )?; + let path = misc_path(); self.drive.grove_insert_if_not_exists( (&path).into(), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs index b0323b9821d..07aca1c1a5b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs @@ -97,8 +97,19 @@ trait BatchTransitionInternalTransformerV0 { transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result>, Error>; - /// The data contract can be of multiple difference versions + fn transform_token_transitions_within_contract_v0( + platform: &PlatformStateRef, + data_contract_id: &Identifier, + validate_against_state: bool, + token_transitions: &Vec<&TokenTransition>, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error>; + /// Transfer token transition fn transform_token_transition_v0( + drive: &Drive, + transaction: TransactionArg, + full_validation: bool, data_contract_fetch_info: Arc, transition: &TokenTransition, ) -> Result, Error>; @@ -129,13 +140,6 @@ trait BatchTransitionInternalTransformerV0 { document_id: Identifier, original_document: &Document, ) -> SimpleConsensusValidationResult; - fn transform_token_transitions_within_contract_v0( - platform: &PlatformStateRef, - data_contract_id: &Identifier, - token_transitions: &Vec<&TokenTransition>, - transaction: TransactionArg, - platform_version: &PlatformVersion, - ) -> Result>, Error>; } impl BatchTransitionTransformerV0 for BatchTransition { @@ -221,6 +225,7 @@ impl BatchTransitionTransformerV0 for BatchTransition { Self::transform_token_transitions_within_contract_v0( platform, data_contract_id, + validate_against_state, token_transitions, transaction, platform_version, @@ -255,6 +260,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { fn transform_token_transitions_within_contract_v0( platform: &PlatformStateRef, data_contract_id: &Identifier, + validate_against_state: bool, token_transitions: &Vec<&TokenTransition>, transaction: TransactionArg, platform_version: &PlatformVersion, @@ -283,6 +289,9 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { .iter() .map(|token_transition| { Self::transform_token_transition_v0( + platform.drive, + transaction, + validate_against_state, data_contract_fetch_info.clone(), token_transition, ) @@ -447,13 +456,16 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { /// The data contract can be of multiple difference versions fn transform_token_transition_v0( + drive: &Drive, + transaction: TransactionArg, + validate_against_state: bool, data_contract_fetch_info: Arc, transition: &TokenTransition, ) -> Result, Error> { match transition { TokenTransition::Burn(token_burn_transition) => { let result = ConsensusValidationResult::::new(); - let token_burn_action = TokenBurnTransitionAction::try_from_borrowed_token_burn_transition_with_contract_lookup(token_burn_transition, |_identifier| { + let token_burn_action = TokenBurnTransitionAction::try_from_borrowed_token_burn_transition_with_contract_lookup(drive, transaction, token_burn_transition, |_identifier| { Ok(data_contract_fetch_info.clone()) })?; @@ -468,7 +480,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { } TokenTransition::Mint(token_mint_transition) => { let result = ConsensusValidationResult::::new(); - let token_mint_action = TokenMintTransitionAction::try_from_borrowed_token_mint_transition_with_contract_lookup(token_mint_transition, |_identifier| { + let token_mint_action = TokenMintTransitionAction::try_from_borrowed_token_mint_transition_with_contract_lookup(drive, transaction, token_mint_transition, |_identifier| { Ok(data_contract_fetch_info.clone()) })?; @@ -483,7 +495,7 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { } TokenTransition::Transfer(token_transfer_transition) => { let result = ConsensusValidationResult::::new(); - let token_transfer_action = TokenTransferTransitionAction::try_from_borrowed_token_transfer_transition_with_contract_lookup(token_transfer_transition, |_identifier| { + let token_transfer_action = TokenTransferTransitionAction::try_from_borrowed_token_transfer_transition_with_contract_lookup(drive, transaction, token_transfer_transition, |_identifier| { Ok(data_contract_fetch_info.clone()) })?; diff --git a/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs b/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs index 816b660e324..a7b41957bfc 100644 --- a/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs @@ -208,6 +208,7 @@ impl Drive { block_info, estimated_costs_only_with_layer_info, &mut drive_operations, + transaction, platform_version, )?; } diff --git a/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs b/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs index cfae17fd1c2..9d6eac54379 100644 --- a/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs +++ b/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs @@ -90,6 +90,7 @@ impl Drive { HashMap, >, drive_operations: &mut Vec, + transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result<(), Error> { match platform_version @@ -113,6 +114,7 @@ impl Drive { block_info, estimated_costs_only_with_layer_info, drive_operations, + transaction, platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { diff --git a/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs b/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs index a413dc7ed28..b28f13f4811 100644 --- a/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs +++ b/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs @@ -12,7 +12,6 @@ use dpp::fee::fee_result::FeeResult; use crate::drive::balances::total_tokens_root_supply_path; use crate::drive::tokens::{token_path, tokens_root_path, TOKEN_BALANCES_KEY}; use crate::error::contract::DataContractError; -use crate::util::grove_operations::BatchInsertTreeApplyType; use crate::util::object_size_info::DriveKeyInfo; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::serialization::PlatformSerializableWithPlatformVersion; @@ -102,6 +101,7 @@ impl Drive { contract, block_info, &mut estimated_costs_only_with_layer_info, + transaction, platform_version, )?; self.apply_batch_low_level_drive_operations( @@ -126,6 +126,7 @@ impl Drive { HashMap, >, drive_operations: &mut Vec, + transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result<(), Error> { let batch_operations = self.insert_contract_operations_v1( @@ -133,6 +134,7 @@ impl Drive { contract, block_info, estimated_costs_only_with_layer_info, + transaction, platform_version, )?; drive_operations.extend(batch_operations); @@ -150,6 +152,7 @@ impl Drive { estimated_costs_only_with_layer_info: &mut Option< HashMap, >, + transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { let mut batch_operations: Vec = self @@ -194,6 +197,16 @@ impl Drive { )?; } + if !contract.groups().is_empty() { + batch_operations.extend(self.add_new_groups_operations( + contract.id(), + contract.groups(), + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + } + Ok(batch_operations) } } diff --git a/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs b/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs index 460055f9036..75d236e331b 100644 --- a/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs +++ b/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs @@ -1,29 +1,23 @@ -use crate::drive::{contract_documents_path, Drive}; +use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; -use crate::util::grove_operations::BatchInsertTreeApplyType; -use crate::util::object_size_info::DriveKeyInfo::KeyRef; -use crate::util::object_size_info::PathKeyInfo::{PathFixedSizeKey, PathFixedSizeKeyRef}; use crate::util::storage_flags::StorageFlags; use dpp::block::block_info::BlockInfo; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::config::v0::DataContractConfigGettersV0; -use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::DataContract; use dpp::fee::fee_result::FeeResult; -use dpp::data_contract::document_type::methods::DocumentTypeV0Methods; use dpp::serialization::PlatformSerializableWithPlatformVersion; -use crate::drive::tokens::{token_path, tokens_root_path, TOKEN_BALANCES_KEY}; use crate::error::contract::DataContractError; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::fee::default_costs::CachedEpochIndexFeeVersions; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; impl Drive { /// Updates a data contract. @@ -241,6 +235,17 @@ impl Drive { platform_version, )?); } + + if !contract.groups().is_empty() { + batch_operations.extend(self.add_new_groups_operations( + contract.id(), + contract.groups(), + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + } + Ok(batch_operations) } } diff --git a/packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs b/packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs new file mode 100644 index 00000000000..c255a565566 --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs @@ -0,0 +1,121 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; + +use dpp::data_contract::group::GroupMemberPower; +use dpp::data_contract::GroupContractPosition; +use dpp::prelude::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Adds an action to the state + pub fn add_group_action( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.group.insert.add_group_action { + 0 => self.add_group_action_v0( + contract_id, + group_contract_position, + action_id, + signer_identity_id, + signer_power, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_group_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds action creation operations to drive operations + pub fn add_group_action_add_to_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.group.insert.add_group_action { + 0 => self.add_group_action_add_to_operations_v0( + contract_id, + group_contract_position, + action_id, + signer_identity_id, + signer_power, + block_info, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_group_action_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to create a new group action + pub fn add_group_action_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_group_action_operations_v0( + contract_id, + group_contract_position, + action_id, + signer_identity_id, + signer_power, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_group_action_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs b/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs new file mode 100644 index 00000000000..71c991d9f40 --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs @@ -0,0 +1,199 @@ +use crate::drive::group::{ + group_action_path, group_action_root_path, group_action_signers_path_vec, ACTION_SIGNERS_KEY, +}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::{BatchInsertApplyType, BatchInsertTreeApplyType, QueryTarget}; +use crate::util::object_size_info::PathKeyInfo::PathFixedSizeKeyRef; +use crate::util::object_size_info::{DriveKeyInfo, PathKeyElementInfo}; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::group::GroupMemberPower; +use dpp::data_contract::GroupContractPosition; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformSerializable; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::element::SumValue; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb_epoch_based_storage_flags::StorageFlags; +use std::collections::HashMap; + +impl Drive { + pub(super) fn add_group_action_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations: Vec = vec![]; + self.add_group_action_add_to_operations_v0( + contract_id, + group_contract_position, + action_id, + signer_identity_id, + signer_power, + block_info, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + Ok(fees) + } + + /// Adds group creation operations to drive operations + pub(super) fn add_group_action_add_to_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + let batch_operations = self.add_new_group_action_operations( + contract_id, + group_contract_position, + action_id, + signer_identity_id, + signer_power, + block_info, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// The operations needed to create a group + pub(super) fn add_group_action_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = vec![]; + + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + let group_action_root_path = group_action_root_path( + contract_id.as_slice(), + group_contract_position_bytes.as_slice(), + ); + let apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertTreeApplyType::StatefulBatchInsertTree + } else { + BatchInsertTreeApplyType::StatelessBatchInsertTree { + in_tree_using_sums: false, + is_sum_tree: false, + flags_len: 0, + } + }; + + // We insert the contract root into the group tree + let inserted_root_action = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKeyRef((group_action_root_path, action_id.as_slice())), + false, + None, + apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if !inserted_root_action { + let group_action_path = group_action_path( + contract_id.as_slice(), + group_contract_position_bytes.as_slice(), + action_id.as_slice(), + ); + + self.batch_insert_empty_sum_tree( + group_action_path, + DriveKeyInfo::KeyRef(ACTION_SIGNERS_KEY), + None, + &mut batch_operations, + &platform_version.drive, + )?; + } + + let signers_path = group_action_signers_path_vec( + contract_id.as_slice(), + *group_contract_position, + action_id.as_slice(), + ); + + let storage_flags = Some(StorageFlags::new_single_epoch( + block_info.epoch.index, + Some(signer_identity_id.to_buffer()), + )); + + let signer_apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertApplyType::StatefulBatchInsert + } else { + BatchInsertApplyType::StatelessBatchInsert { + in_tree_using_sums: true, + target: QueryTarget::QueryTargetValue(8), + } + }; + + self.batch_insert_sum_item_if_not_exists( + PathKeyElementInfo::PathKeyElement(( + signers_path, + signer_identity_id.to_vec(), + Element::SumItem( + signer_power as SumValue, + StorageFlags::map_to_some_element_flags(storage_flags.as_ref()), + ), + )), + true, + signer_apply_type, + transaction, + &mut batch_operations, + &platform_version.drive, + )?; + + Ok(batch_operations) + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs b/packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs new file mode 100644 index 00000000000..a5fe50e5458 --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs @@ -0,0 +1,99 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; + +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::prelude::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::{BTreeMap, HashMap}; + +mod v0; + +impl Drive { + /// Adds groups to the state. + pub fn add_new_groups( + &self, + contract_id: Identifier, + groups: &BTreeMap, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_new_groups_v0( + contract_id, + groups, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_groups".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds groups creation operations to drive operations + pub fn add_new_groups_add_to_operations( + &self, + contract_id: Identifier, + groups: &BTreeMap, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_new_groups_add_to_operations_v0( + contract_id, + groups, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_groups_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to create groups + pub fn add_new_groups_operations( + &self, + contract_id: Identifier, + groups: &BTreeMap, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_new_groups_operations_v0( + contract_id, + groups, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_groups_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs b/packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs new file mode 100644 index 00000000000..c8de9a1432d --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs @@ -0,0 +1,251 @@ +use crate::drive::group::{group_contract_path, group_path_vec, group_root_path, GROUP_INFO_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::BatchInsertTreeApplyType; +use crate::util::object_size_info::PathKeyInfo::PathFixedSizeKey; +use crate::util::object_size_info::{DriveKeyInfo, PathKeyElementInfo}; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformSerializable; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::{BTreeMap, HashMap}; + +impl Drive { + /// Adds a group by inserting a new group subtree structure to the `Identities` subtree. + pub(super) fn add_new_groups_v0( + &self, + contract_id: Identifier, + groups: &BTreeMap, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations: Vec = vec![]; + self.add_new_groups_add_to_operations_v0( + contract_id, + groups, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + Ok(fees) + } + + /// Adds group creation operations to drive operations + pub(super) fn add_new_groups_add_to_operations_v0( + &self, + contract_id: Identifier, + groups: &BTreeMap, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + let batch_operations = self.add_new_groups_operations( + contract_id, + groups, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// The operations needed to create a group + pub(super) fn add_new_groups_operations_v0( + &self, + contract_id: Identifier, + groups: &BTreeMap, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = vec![]; + + let group_tree_path = group_root_path(); + + let apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertTreeApplyType::StatefulBatchInsertTree + } else { + BatchInsertTreeApplyType::StatelessBatchInsertTree { + in_tree_using_sums: false, + is_sum_tree: false, + flags_len: 0, + } + }; + + // We insert the contract root into the group tree + let inserted = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKey((group_tree_path, contract_id.to_vec())), + false, + None, + apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if inserted { + for (group_pos, group) in groups { + let group_pos_bytes = group_pos.to_be_bytes().to_vec(); + let path = group_contract_path(contract_id.as_slice()); + self.batch_insert_empty_tree( + path, + DriveKeyInfo::Key(group_pos_bytes.clone()), + None, + &mut batch_operations, + &platform_version.drive, + )?; + let group_path = group_path_vec(contract_id.as_slice(), *group_pos); + + let serialized_group_info = group.serialize_to_bytes()?; + let info_item = Element::Item(serialized_group_info, None); + self.batch_insert( + PathKeyElementInfo::PathKeyElement::<0>(( + group_path, + GROUP_INFO_KEY.to_vec(), + info_item, + )), + &mut batch_operations, + &platform_version.drive, + )?; + } + } else { + for (group_pos, group) in groups { + let group_pos_bytes = group_pos.to_be_bytes().to_vec(); + let path = group_contract_path(contract_id.as_slice()); + let inserted = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKey((path, group_pos_bytes)), + false, + None, + apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if inserted { + let group_path = group_path_vec(contract_id.as_slice(), *group_pos); + + let serialized_group_info = group.serialize_to_bytes()?; + let info_item = Element::Item(serialized_group_info, None); + self.batch_insert( + PathKeyElementInfo::PathKeyElement::<0>(( + group_path, + GROUP_INFO_KEY.to_vec(), + info_item, + )), + &mut batch_operations, + &platform_version.drive, + )?; + } + } + } + + Ok(batch_operations) + } +} + +#[cfg(test)] +mod tests { + use crate::util::test_helpers::setup::{setup_drive, setup_drive_with_initial_state_structure}; + + use dpp::block::block_info::BlockInfo; + + use dpp::version::PlatformVersion; + + #[test] + fn test_insert_and_fetch_group_v0() { + let drive = setup_drive(None); + let platform_version = PlatformVersion::first(); + + let transaction = drive.grove.start_transaction(); + + drive + .create_initial_state_structure(Some(&transaction), platform_version) + .expect("expected to create root tree successfully"); + + let group = Identity::random_group(5, Some(12345), platform_version) + .expect("expected a random group"); + + drive + .add_new_groups_v0( + group.clone(), + false, + &BlockInfo::default(), + true, + Some(&transaction), + platform_version, + ) + .expect("expected to insert group"); + + let fetched_group = drive + .fetch_full_group(group.id().to_buffer(), Some(&transaction), platform_version) + .expect("should fetch an group") + .expect("should have an group"); + + assert_eq!(group, fetched_group); + } + + #[test] + fn test_insert_group_v0() { + let drive = setup_drive_with_initial_state_structure(None); + + let db_transaction = drive.grove.start_transaction(); + + let platform_version = PlatformVersion::latest(); + + let group = Identity::random_group(5, Some(12345), platform_version) + .expect("expected a random group"); + + drive + .add_new_groups_v0( + group, + false, + &BlockInfo::default(), + true, + Some(&db_transaction), + platform_version, + ) + .expect("expected to insert group"); + + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + } +} diff --git a/packages/rs-drive/src/drive/group/insert/mod.rs b/packages/rs-drive/src/drive/group/insert/mod.rs new file mode 100644 index 00000000000..344133883d6 --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/mod.rs @@ -0,0 +1,2 @@ +mod add_group_action; +mod add_new_groups; diff --git a/packages/rs-drive/src/drive/group/mod.rs b/packages/rs-drive/src/drive/group/mod.rs new file mode 100644 index 00000000000..b65a51ee37f --- /dev/null +++ b/packages/rs-drive/src/drive/group/mod.rs @@ -0,0 +1,152 @@ +use crate::drive::RootTree; +use dpp::data_contract::GroupContractPosition; + +mod insert; +pub const GROUP_INFO_KEY: &[u8; 1] = b"I"; +pub const GROUP_ACTIONS_KEY: &[u8; 1] = b"M"; +pub const ACTION_INFO_KEY: &[u8; 1] = b"I"; +pub const ACTION_SIGNERS_KEY: &[u8; 1] = b"S"; + +/// Group root path +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_root_path() -> [&'static [u8]; 1] { + [Into::<&[u8; 1]>::into(RootTree::GroupActions)] +} + +/// Group root path vector +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_root_path_vec() -> Vec> { + vec![vec![RootTree::GroupActions as u8]] +} + +/// Group path +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_contract_path(contract_id: &[u8]) -> [&[u8]; 2] { + [Into::<&[u8; 1]>::into(RootTree::GroupActions), contract_id] +} + +/// Group path vector +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_contract_path_vec(contract_id: &[u8]) -> Vec> { + vec![vec![RootTree::GroupActions as u8], contract_id.to_vec()] +} + +/// Group path +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], +) -> [&'a [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + ] +} + +/// Group path vector +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + ] +} + +/// Group action path +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_action_root_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], +) -> [&'a [u8]; 4] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_ACTIONS_KEY, + ] +} + +/// Group action path vector +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_action_root_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_ACTIONS_KEY.to_vec(), + ] +} + +/// Group path +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_action_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], + action_id: &'a [u8], +) -> [&'a [u8]; 5] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_ACTIONS_KEY, + action_id, + ] +} + +/// Group path vector +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_action_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, + action_id: &[u8], +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_ACTIONS_KEY.to_vec(), + action_id.to_vec(), + ] +} + +/// Group path +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_action_signers_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], + action_id: &'a [u8], +) -> [&'a [u8]; 6] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_ACTIONS_KEY, + action_id, + ACTION_SIGNERS_KEY, + ] +} + +/// Group path vector +#[cfg(any(feature = "server", feature = "verify"))] +pub(crate) fn group_action_signers_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, + action_id: &[u8], +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_ACTIONS_KEY.to_vec(), + action_id.to_vec(), + ACTION_SIGNERS_KEY.to_vec(), + ] +} diff --git a/packages/rs-drive/src/drive/initialization/v1/mod.rs b/packages/rs-drive/src/drive/initialization/v1/mod.rs index 80b893444ac..0e0db5c11bc 100644 --- a/packages/rs-drive/src/drive/initialization/v1/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v1/mod.rs @@ -4,7 +4,7 @@ use crate::drive::balances::TOTAL_TOKEN_SUPPLIES_STORAGE_KEY; use crate::util::batch::GroveDbOpBatch; use crate::drive::system::misc_path_vec; -use crate::drive::Drive; +use crate::drive::{Drive, RootTree}; use crate::error::Error; use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; @@ -14,6 +14,7 @@ use crate::drive::identity::withdrawals::paths::{ }; use dpp::version::PlatformVersion; use grovedb::{Element, TransactionArg}; +use grovedb_path::SubtreePath; impl Drive { /// Creates the initial state structure. @@ -25,6 +26,15 @@ impl Drive { let drive_version = &platform_version.drive; self.create_initial_state_structure_top_level_0(transaction, platform_version)?; + self.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::GroupActions as u8], + transaction, + None, + &mut vec![], + drive_version, + )?; + // On lower layers we can use batching let mut batch = @@ -50,21 +60,6 @@ impl Drive { Element::empty_tree(), ); - // We are adding the withdrawal transactions sum amount tree - let path = get_withdrawal_root_path_vec(); - - batch.add_insert( - path.clone(), - WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY.to_vec(), - Element::empty_sum_tree(), - ); - - batch.add_insert( - path, - WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY.to_vec(), - Element::empty_tree(), - ); - Ok(()) } } diff --git a/packages/rs-drive/src/drive/mod.rs b/packages/rs-drive/src/drive/mod.rs index f23dbdf2d90..4a303c4e695 100644 --- a/packages/rs-drive/src/drive/mod.rs +++ b/packages/rs-drive/src/drive/mod.rs @@ -48,6 +48,7 @@ pub(crate) mod prefunded_specialized_balances; #[cfg(any(feature = "server", feature = "verify"))] pub mod votes; +pub mod group; #[cfg(feature = "server")] mod shared; mod tokens; @@ -79,10 +80,10 @@ pub struct Drive { // DataContract_Documents 64 // / \ // Identities 32 Balances 96 -// / \ / \ -// Token_Balances 16 Pools 48 WithdrawalTransactions 80 Votes 112 -// / \ / \ / / \ -// NUPKH->I 8 UPKH->I 24 PreFundedSpecializedBalances 40 Masternode Lists 56 (reserved) SpentAssetLockTransactions 72 Misc 104 Versions 120 +// / \ / \ +// Token_Balances 16 Pools 48 WithdrawalTransactions 80 Votes 112 +// / \ / \ / \ / \ +// NUPKH->I 8 UPKH->I 24 PreFundedSpecializedBalances 40 Masternode Lists 56 (reserved) SpentAssetLockTransactions 72 GroupActions 88 Misc 104 Versions 120 /// Keys for the root tree. #[cfg(any(feature = "server", feature = "verify"))] @@ -119,6 +120,8 @@ pub enum RootTree { Versions = 120, /// Registered votes Votes = 112, + /// Group actions + GroupActions = 88, } #[cfg(any(feature = "server", feature = "verify"))] @@ -141,6 +144,7 @@ impl fmt::Display for RootTree { RootTree::Tokens => "TokenBalances", RootTree::Versions => "Versions", RootTree::Votes => "Votes", + RootTree::GroupActions => "GroupActions", }; write!(f, "{}", variant_name) } @@ -209,6 +213,7 @@ impl From for &'static [u8; 1] { RootTree::NonUniquePublicKeyKeyHashesToIdentities => &[8], RootTree::Versions => &[120], RootTree::Votes => &[112], + RootTree::GroupActions => &[88], } } } diff --git a/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs index 98d5e667bbc..86d2103a4ea 100644 --- a/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs @@ -236,57 +236,126 @@ mod tests { ); } - // #[test] - // fn should_prove_multiple_identity_single_token_balances() { - // let drive = setup_drive_with_initial_state_structure(None); - // let platform_version = PlatformVersion::latest(); - // let identities: BTreeMap<[u8; 32], Identity> = - // Identity::random_identities(10, 3, Some(14), platform_version) - // .expect("expected to get random identities") - // .into_iter() - // .map(|identity| (identity.id().to_buffer(), identity)) - // .collect(); - // - // let mut rng = StdRng::seed_from_u64(293); - // - // let token_id: [u8; 32] = rng.gen(); - // - // drive.add_new_token(token_id); - // - // for identity in identities.values() { - // drive - // .add_new_identity( - // identity.clone(), - // false, - // &BlockInfo::default(), - // true, - // None, - // platform_version, - // ) - // .expect("expected to add an identity"); - // } - // let identity_ids = identities.keys().copied().collect::>(); - // let identity_balances = identities - // .into_iter() - // .map(|(id, identity)| (id, Some(identity.balance()))) - // .collect::>>(); - // let proof = drive - // .prove_many_identity_token_balances( - // identity_ids.as_slice(), - // None, - // &platform_version.drive, - // ) - // .expect("should not error when proving an identity"); - // - // let (_, proved_identity_balances): ([u8; 32], BTreeMap<[u8; 32], Option>) = - // Drive::verify_identity_balances_for_identity_ids( - // proof.as_slice(), - // false, - // identity_ids.as_slice(), - // platform_version, - // ) - // .expect("expect that this be verified"); - // - // assert_eq!(proved_identity_balances, identity_balances); - // } + #[test] + fn should_prove_multiple_identity_single_token_balances_after_transfer() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id().to_buffer(); + + let identity_2 = Identity::random_identity(3, Some(15), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity_1.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .add_new_identity( + identity_2.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + drive + .token_mint( + token_id.to_buffer(), + identity_1.id().to_buffer(), + 100000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token"); + + drive + .token_transfer( + token_id.to_buffer(), + identity_1.id().to_buffer(), + identity_2.id().to_buffer(), + 30000, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to transfer token"); + let proof = drive + .prove_identities_token_balances_v0( + token_id.to_buffer(), + &vec![identity_1.id().to_buffer(), identity_2.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity_1.id().to_buffer(), identity_2.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!( + proved_identity_balance, + BTreeMap::from([(identity_1_id, Some(70000)), (identity_2_id, Some(30000))]) + ); + } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/mod.rs index 33447ccc016..8af281a02bf 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/mod.rs @@ -1,5 +1,7 @@ use derive_more::From; use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; +use dpp::data_contract::GroupContractPosition; +use dpp::group::GroupStateTransitionInfo; use dpp::platform_value::Identifier; use dpp::prelude::IdentityNonce; use std::sync::Arc; @@ -62,4 +64,16 @@ impl TokenBaseTransitionActionAccessorsV0 for TokenBaseTransitionAction { TokenBaseTransitionAction::V0(v0) => v0.identity_contract_nonce(), } } + + fn store_in_group(&self) -> Option { + match self { + TokenBaseTransitionAction::V0(v0) => v0.store_in_group(), + } + } + + fn perform_action(&self) -> bool { + match self { + TokenBaseTransitionAction::V0(v0) => v0.perform_action(), + } + } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/transformer.rs index 46939f2f56e..4143ca11a86 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/transformer.rs @@ -1,20 +1,25 @@ use dpp::platform_value::Identifier; use std::sync::Arc; - +use grovedb::TransactionArg; use dpp::ProtocolError; use dpp::state_transition::batch_transition::token_base_transition::TokenBaseTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; use crate::state_transition_action::document::documents_batch::document_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionV0}; impl TokenBaseTransitionAction { /// from base transition with contract lookup pub fn try_from_base_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: TokenBaseTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { match value { TokenBaseTransition::V0(v0) => Ok( TokenBaseTransitionActionV0::try_from_base_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )? @@ -25,11 +30,13 @@ impl TokenBaseTransitionAction { /// from borrowed base transition with contract lookup pub fn try_from_borrowed_base_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: &TokenBaseTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { match value { - TokenBaseTransition::V0(v0) => Ok(TokenBaseTransitionActionV0::try_from_borrowed_base_transition_with_contract_lookup(v0, get_data_contract)?.into()), + TokenBaseTransition::V0(v0) => Ok(TokenBaseTransitionActionV0::try_from_borrowed_base_transition_with_contract_lookup(drive, transaction, v0, get_data_contract)?.into()), } } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/mod.rs index b6c63703c56..1ec510b4037 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/mod.rs @@ -3,6 +3,8 @@ use crate::error::Error; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; +use dpp::data_contract::GroupContractPosition; +use dpp::group::GroupStateTransitionInfo; use dpp::identifier::Identifier; use dpp::prelude::IdentityNonce; use dpp::ProtocolError; @@ -22,6 +24,13 @@ pub struct TokenBaseTransitionActionV0 { pub token_contract_position: u16, /// A potential data contract pub data_contract: Arc, + /// Using group multi party rules for authentication + /// If this is set we should store in group + pub store_in_group: Option, + /// Should the action be performed. + /// This is true if we don't store in group. + /// And also true if we store in group and with this have enough signatures to perform the action + pub perform_action: bool, } /// Token base transition action accessors v0 @@ -46,6 +55,12 @@ pub trait TokenBaseTransitionActionAccessorsV0 { /// Gets the token configuration associated to the action fn token_configuration(&self) -> Result<&TokenConfiguration, Error>; + + /// Gets the store_in_group field (optional) + fn store_in_group(&self) -> Option; + + /// Gets the perform_action field + fn perform_action(&self) -> bool; } impl TokenBaseTransitionActionAccessorsV0 for TokenBaseTransitionActionV0 { @@ -86,4 +101,12 @@ impl TokenBaseTransitionActionAccessorsV0 for TokenBaseTransitionActionV0 { ), ))) } + + fn store_in_group(&self) -> Option { + self.store_in_group + } + + fn perform_action(&self) -> bool { + self.perform_action + } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/transformer.rs index 1b4efe5527c..ffd5ad44c01 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_base_transition_action/v0/transformer.rs @@ -1,15 +1,20 @@ -use std::sync::Arc; - +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::group::GroupStateTransitionInfo; use dpp::platform_value::Identifier; +use grovedb::TransactionArg; +use std::sync::Arc; use dpp::ProtocolError; use dpp::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; use crate::state_transition_action::document::documents_batch::document_transition::token_base_transition_action::TokenBaseTransitionActionV0; impl TokenBaseTransitionActionV0 { /// try from base transition with contract lookup pub fn try_from_base_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: TokenBaseTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -18,17 +23,34 @@ impl TokenBaseTransitionActionV0 { data_contract_id, identity_contract_nonce, token_id, + using_group, } = value; + + let data_contract = get_data_contract(data_contract_id)?; + + let (store_in_group, perform_action) = match using_group { + None => (None, true), + Some(GroupStateTransitionInfo { + group_contract_position, + action_id, + }) => { + drive.fetch_action_id_signers(data_contract_id, group_contract_position, action_id) + } + }; Ok(TokenBaseTransitionActionV0 { token_id, identity_contract_nonce, token_contract_position, - data_contract: get_data_contract(data_contract_id)?, + data_contract, + store_in_group, + perform_action, }) } /// try from borrowed base transition with contract lookup pub fn try_from_borrowed_base_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: &TokenBaseTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -37,12 +59,15 @@ impl TokenBaseTransitionActionV0 { data_contract_id, identity_contract_nonce, token_id, + using_group, } = value; Ok(TokenBaseTransitionActionV0 { token_id: *token_id, identity_contract_nonce: *identity_contract_nonce, token_contract_position: *token_contract_position, data_contract: get_data_contract(*data_contract_id)?, + store_in_group: None, + perform_action: false, }) } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/transformer.rs index 9e7c757a102..8413eb68813 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/transformer.rs @@ -1,13 +1,14 @@ -use std::sync::Arc; - use dpp::platform_value::Identifier; use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; use crate::drive::contract::DataContractFetchInfo; use crate::state_transition_action::document::documents_batch::document_transition::token_burn_transition_action::{ TokenBurnTransitionAction, TokenBurnTransitionActionV0, }; use dpp::state_transition::batch_transition::token_burn_transition::TokenBurnTransition; +use crate::drive::Drive; /// Implement methods to transform a `TokenBurnTransition` into a `TokenBurnTransitionAction`. impl TokenBurnTransitionAction { @@ -22,6 +23,8 @@ impl TokenBurnTransitionAction { /// /// * `Result` - A `TokenBurnTransitionAction` if successful, otherwise `ProtocolError`. pub fn try_from_token_burn_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: TokenBurnTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -29,6 +32,8 @@ impl TokenBurnTransitionAction { TokenBurnTransition::V0(v0) => { let v0_action = TokenBurnTransitionActionV0::try_from_token_burn_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )?; @@ -48,12 +53,16 @@ impl TokenBurnTransitionAction { /// /// * `Result` - A `TokenBurnTransitionAction` if successful, otherwise `ProtocolError`. pub fn try_from_borrowed_token_burn_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: &TokenBurnTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { match value { TokenBurnTransition::V0(v0) => { let v0_action = TokenBurnTransitionActionV0::try_from_borrowed_token_burn_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/v0/transformer.rs index 09bb907014b..9c71c39315c 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_burn_transition_action/v0/transformer.rs @@ -1,10 +1,11 @@ -use std::sync::Arc; - use dpp::identifier::Identifier; use dpp::state_transition::batch_transition::token_burn_transition::v0::TokenBurnTransitionV0; use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; use crate::state_transition_action::document::documents_batch::document_transition::token_base_transition_action::TokenBaseTransitionAction; use crate::state_transition_action::document::documents_batch::document_transition::token_burn_transition_action::v0::TokenBurnTransitionActionV0; @@ -20,6 +21,8 @@ impl TokenBurnTransitionActionV0 { /// /// * `Result` - A `TokenBurnTransitionActionV0` if successful, else `ProtocolError`. pub fn try_from_token_burn_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: TokenBurnTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -30,6 +33,8 @@ impl TokenBurnTransitionActionV0 { } = value; let base_action = TokenBaseTransitionAction::try_from_base_transition_with_contract_lookup( + drive, + transaction, base, get_data_contract, )?; @@ -52,6 +57,8 @@ impl TokenBurnTransitionActionV0 { /// /// * `Result` - A `TokenBurnTransitionActionV0` if successful, else `ProtocolError`. pub fn try_from_borrowed_token_burn_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: &TokenBurnTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -63,6 +70,8 @@ impl TokenBurnTransitionActionV0 { let base_action = TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + transaction, base, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/mod.rs index 405337029c0..10262ce08b8 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/mod.rs @@ -13,7 +13,7 @@ use crate::state_transition_action::document::documents_batch::document_transiti #[derive(Debug, Clone, From)] pub enum TokenMintTransitionAction { /// v0 - V0(TokenIssuanceTransitionActionV0), + V0(TokenMintTransitionActionV0), } impl TokenMintTransitionActionAccessorsV0 for TokenMintTransitionAction { diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/transformer.rs index 1ad37b14bed..03db3c62813 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/transformer.rs @@ -1,34 +1,37 @@ -use std::sync::Arc; - use dpp::platform_value::Identifier; use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::token_mint_transition_action::{ - TokenMintTransitionAction, TokenIssuanceTransitionActionV0, -}; -use dpp::state_transition::batch_transition::token_issuance_transition::TokenIssuanceTransition; +use crate::state_transition_action::document::documents_batch::document_transition::token_mint_transition_action::{TokenMintTransitionActionV0, TokenMintTransitionAction}; +use dpp::state_transition::batch_transition::token_issuance_transition::TokenMintTransition; +use crate::drive::Drive; -/// Implement methods to transform a `TokenIssuanceTransition` into a `TokenIssuanceTransitionAction`. +/// Implement methods to transform a `TokenMintTransition` into a `TokenMintTransitionAction`. impl TokenMintTransitionAction { - /// Transform a `TokenIssuanceTransition` into a `TokenIssuanceTransitionAction` using the provided data contract lookup. + /// Transform a `TokenMintTransition` into a `TokenMintTransitionAction` using the provided data contract lookup. /// /// # Arguments /// - /// * `value` - A `TokenIssuanceTransition` instance. + /// * `value` - A `TokenMintTransition` instance. /// * `get_data_contract` - A closure that fetches the DataContractFetchInfo given a contract ID. /// /// # Returns /// - /// * `Result` - A `TokenIssuanceTransitionAction` if successful, otherwise `ProtocolError`. - pub fn from_token_issuance_transition_with_contract_lookup( - value: TokenIssuanceTransition, + /// * `Result` - A `TokenMintTransitionAction` if successful, otherwise `ProtocolError`. + pub fn from_token_mint_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, + value: TokenMintTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { match value { - TokenIssuanceTransition::V0(v0) => { + TokenMintTransition::V0(v0) => { let v0_action = - TokenIssuanceTransitionActionV0::try_from_token_issuance_transition_with_contract_lookup( + TokenMintTransitionActionV0::try_from_token_mint_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )?; @@ -37,23 +40,27 @@ impl TokenMintTransitionAction { } } - /// Transform a borrowed `TokenIssuanceTransition` into a `TokenIssuanceTransitionAction` using the provided data contract lookup. + /// Transform a borrowed `TokenMintTransition` into a `TokenMintTransitionAction` using the provided data contract lookup. /// /// # Arguments /// - /// * `value` - A reference to a `TokenIssuanceTransition`. + /// * `value` - A reference to a `TokenMintTransition`. /// * `get_data_contract` - A closure that fetches the DataContractFetchInfo given a contract ID. /// /// # Returns /// - /// * `Result` - A `TokenIssuanceTransitionAction` if successful, otherwise `ProtocolError`. + /// * `Result` - A `TokenMintTransitionAction` if successful, otherwise `ProtocolError`. pub fn try_from_borrowed_token_mint_transition_with_contract_lookup( - value: &TokenIssuanceTransition, + drive: &Drive, + transaction: TransactionArg, + value: &TokenMintTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { match value { - TokenIssuanceTransition::V0(v0) => { - let v0_action = TokenIssuanceTransitionActionV0::try_from_borrowed_token_issuance_transition_with_contract_lookup( + TokenMintTransition::V0(v0) => { + let v0_action = TokenMintTransitionActionV0::try_from_borrowed_token_mint_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/mod.rs index 5d158482d68..5af141cff4a 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/mod.rs @@ -7,7 +7,7 @@ use crate::state_transition_action::document::documents_batch::document_transiti /// Token issuance transition action v0 #[derive(Debug, Clone)] -pub struct TokenIssuanceTransitionActionV0 { +pub struct TokenMintTransitionActionV0 { /// Base token transition action pub base: TokenBaseTransitionAction, /// The amount of tokens to create @@ -73,7 +73,7 @@ pub trait TokenMintTransitionActionAccessorsV0 { fn set_public_note(&mut self, public_note: Option); } -impl TokenMintTransitionActionAccessorsV0 for TokenIssuanceTransitionActionV0 { +impl TokenMintTransitionActionAccessorsV0 for TokenMintTransitionActionV0 { fn base(&self) -> &TokenBaseTransitionAction { &self.base } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/transformer.rs index bedc0d48c7c..4e3fca8997d 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_mint_transition_action/v0/transformer.rs @@ -1,32 +1,35 @@ use std::sync::Arc; - +use grovedb::TransactionArg; use dpp::identifier::Identifier; -use dpp::state_transition::batch_transition::token_issuance_transition::v0::TokenIssuanceTransitionV0; +use dpp::state_transition::batch_transition::token_issuance_transition::v0::TokenMintTransitionV0; use dpp::ProtocolError; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use dpp::tokens::errors::TokenError; use crate::drive::contract::DataContractFetchInfo; use crate::state_transition_action::document::documents_batch::document_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; -use crate::state_transition_action::document::documents_batch::document_transition::token_mint_transition_action::v0::TokenIssuanceTransitionActionV0; +use crate::state_transition_action::document::documents_batch::document_transition::token_mint_transition_action::v0::TokenMintTransitionActionV0; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use crate::drive::Drive; -impl TokenIssuanceTransitionActionV0 { - /// Attempt to convert a `TokenIssuanceTransitionV0` into a `TokenIssuanceTransitionActionV0` using a data contract lookup function. +impl TokenMintTransitionActionV0 { + /// Attempt to convert a `TokenMintTransitionV0` into a `TokenMintTransitionActionV0` using a data contract lookup function. /// /// # Arguments /// - /// * `value` - A `TokenIssuanceTransitionV0` from which to derive the action + /// * `value` - A `TokenMintTransitionV0` from which to derive the action /// * `get_data_contract` - A closure that, given a `data_contract_id`, returns an `Arc` /// /// # Returns /// - /// * `Result` - A `TokenIssuanceTransitionActionV0` if successful, else `ProtocolError`. - pub fn try_from_token_issuance_transition_with_contract_lookup( - value: TokenIssuanceTransitionV0, + /// * `Result` - A `TokenMintTransitionActionV0` if successful, else `ProtocolError`. + pub fn try_from_token_mint_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, + value: TokenMintTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { - let TokenIssuanceTransitionV0 { + let TokenMintTransitionV0 { base, issued_to_identity_id, amount, @@ -36,6 +39,8 @@ impl TokenIssuanceTransitionActionV0 { let position = base.token_contract_position(); let base_action = TokenBaseTransitionAction::try_from_base_transition_with_contract_lookup( + drive, + transaction, base, get_data_contract, )?; @@ -55,7 +60,7 @@ impl TokenIssuanceTransitionActionV0 { TokenError::DestinationIdentityForMintingNotSetError.into(), ))?; - Ok(TokenIssuanceTransitionActionV0 { + Ok(TokenMintTransitionActionV0 { base: base_action, mint_amount: amount, identity_balance_holder_id, @@ -63,21 +68,23 @@ impl TokenIssuanceTransitionActionV0 { }) } - /// Attempt to convert a borrowed `TokenIssuanceTransitionV0` into a `TokenIssuanceTransitionActionV0` using a data contract lookup function. + /// Attempt to convert a borrowed `TokenMintTransitionV0` into a `TokenMintTransitionActionV0` using a data contract lookup function. /// /// # Arguments /// - /// * `value` - A reference to a `TokenIssuanceTransitionV0` from which to derive the action + /// * `value` - A reference to a `TokenMintTransitionV0` from which to derive the action /// * `get_data_contract` - A closure that, given a `data_contract_id`, returns an `Arc` /// /// # Returns /// - /// * `Result` - A `TokenIssuanceTransitionActionV0` if successful, else `ProtocolError`. - pub fn try_from_borrowed_token_issuance_transition_with_contract_lookup( - value: &TokenIssuanceTransitionV0, + /// * `Result` - A `TokenMintTransitionActionV0` if successful, else `ProtocolError`. + pub fn try_from_borrowed_token_mint_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, + value: &TokenMintTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { - let TokenIssuanceTransitionV0 { + let TokenMintTransitionV0 { base, issued_to_identity_id, amount, @@ -86,6 +93,8 @@ impl TokenIssuanceTransitionActionV0 { let base_action = TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + transaction, base, get_data_contract, )?; @@ -105,7 +114,7 @@ impl TokenIssuanceTransitionActionV0 { TokenError::DestinationIdentityForMintingNotSetError.into(), ))?; - Ok(TokenIssuanceTransitionActionV0 { + Ok(TokenMintTransitionActionV0 { base: base_action, mint_amount: *amount, identity_balance_holder_id, diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/transformer.rs index 708eb7004b7..99a2af6f1d2 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/transformer.rs @@ -1,9 +1,10 @@ use std::sync::Arc; - +use grovedb::TransactionArg; use dpp::platform_value::Identifier; use dpp::ProtocolError; use dpp::state_transition::batch_transition::TokenTransferTransition; use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; use crate::state_transition_action::document::documents_batch::document_transition::token_transfer_transition_action::TokenTransferTransitionAction; use crate::state_transition_action::document::documents_batch::document_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionV0; @@ -20,6 +21,8 @@ impl TokenTransferTransitionAction { /// /// * `Result` - A `TokenTransferTransitionAction` if successful, otherwise `ProtocolError`. pub fn from_token_transfer_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: TokenTransferTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -27,6 +30,8 @@ impl TokenTransferTransitionAction { TokenTransferTransition::V0(v0) => { let v0_action = TokenTransferTransitionActionV0::try_from_token_transfer_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )?; @@ -46,12 +51,16 @@ impl TokenTransferTransitionAction { /// /// * `Result` - A `TokenTransferTransitionAction` if successful, otherwise `ProtocolError`. pub fn try_from_borrowed_token_transfer_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: &TokenTransferTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { match value { TokenTransferTransition::V0(v0) => { let v0_action = TokenTransferTransitionActionV0::try_from_borrowed_token_transfer_transition_with_contract_lookup( + drive, + transaction, v0, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/v0/transformer.rs index dec31daefc3..2c27cde2acf 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/token_transfer_transition_action/v0/transformer.rs @@ -1,16 +1,19 @@ -use std::sync::Arc; - use dpp::identifier::Identifier; use dpp::state_transition::batch_transition::token_transfer_transition::v0::TokenTransferTransitionV0; use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; use crate::state_transition_action::document::documents_batch::document_transition::token_base_transition_action::TokenBaseTransitionAction; use crate::state_transition_action::document::documents_batch::document_transition::token_transfer_transition_action::TokenTransferTransitionActionV0; impl TokenTransferTransitionActionV0 { /// Convert a `TokenTransferTransitionV0` into a `TokenTransferTransitionActionV0` using contract lookup pub fn try_from_token_transfer_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: TokenTransferTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -24,6 +27,8 @@ impl TokenTransferTransitionActionV0 { } = value; let base_action = TokenBaseTransitionAction::try_from_base_transition_with_contract_lookup( + drive, + transaction, base, get_data_contract, )?; @@ -40,6 +45,8 @@ impl TokenTransferTransitionActionV0 { /// Convert a borrowed `TokenTransferTransitionV0` into a `TokenTransferTransitionActionV0` using contract lookup pub fn try_from_borrowed_token_transfer_transition_with_contract_lookup( + drive: &Drive, + transaction: TransactionArg, value: &TokenTransferTransitionV0, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -54,6 +61,8 @@ impl TokenTransferTransitionActionV0 { let base_action = TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + transaction, &base, get_data_contract, )?; diff --git a/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs b/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs index 8fba7f7970e..68bac3502d1 100644 --- a/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs +++ b/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs @@ -52,6 +52,7 @@ enum KnownPath { TokenBalancesRoot, //Level 1 VersionsRoot, //Level 1 VotesRoot, //Level 1 + GroupActionsRoot, //Level 1 } impl From for KnownPath { @@ -74,6 +75,7 @@ impl From for KnownPath { RootTree::Tokens => KnownPath::TokenBalancesRoot, RootTree::Versions => KnownPath::VersionsRoot, RootTree::Votes => KnownPath::VotesRoot, + RootTree::GroupActions => KnownPath::GroupActionsRoot, } } } diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs new file mode 100644 index 00000000000..943dac0b8e0 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs @@ -0,0 +1,71 @@ +mod v0; + +use crate::util::grove_operations::BatchInsertApplyType; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::object_size_info::PathKeyElementInfo; + +use dpp::version::drive_versions::DriveVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Attempts to batch insert a sum item at the specified path and key if it doesn't already exist. + /// This method dispatches to the appropriate version of the `batch_insert_sum_item_if_not_exists` function + /// based on the version of the drive. Currently, version `0` is supported. + /// + /// # Parameters + /// * `path_key_element_info`: Contains the path, key, and element information to be inserted. + /// * `error_if_exists`: A flag that determines whether an error is returned if a sum item already exists at the given path and key. + /// * `apply_type`: Defines the batch insert type, such as stateless or stateful insertion. + /// * `transaction`: The transaction argument used for the operation. + /// * `drive_operations`: A mutable reference to a vector that collects low-level drive operations to be executed. + /// * `drive_version`: The version of the drive that influences the behavior of the batch insert operation. + /// + /// # Returns + /// * `Ok(())` if the batch insert is successful. + /// * `Err(Error)` if the operation fails, including an error for unknown version mismatches. + /// + /// # Description + /// This function checks the version of the drive's batch methods and dispatches the operation to the appropriate version of + /// `batch_insert_sum_item_if_not_exists`. Currently, only version `0` is supported, which delegates to the function + /// `batch_insert_sum_item_if_not_exists_v0`. If the drive version is not supported, an error is returned. + /// + /// In version `0`, the function performs the following: + /// - Checks if a sum item exists at the specified path and key. + /// - If the sum item exists and `error_if_exists` is true, an error is returned. + /// - If no sum item exists, a new sum item is inserted at the path and key. + /// + /// This method allows flexibility for future versions of the drive to implement different behaviors for batch insertion. + pub fn batch_insert_sum_item_if_not_exists( + &self, + path_key_element_info: PathKeyElementInfo, + error_if_exists: bool, + apply_type: BatchInsertApplyType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .grove_methods + .batch + .batch_insert_sum_item_if_not_exists + { + 0 => self.batch_insert_sum_item_if_not_exists_v0( + path_key_element_info, + error_if_exists, + apply_type, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "batch_insert_sum_item_if_not_exists".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs new file mode 100644 index 00000000000..13e88ba1ca9 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs @@ -0,0 +1,224 @@ +use crate::util::grove_operations::BatchInsertApplyType; +use crate::util::object_size_info::PathKeyElementInfo::{ + PathFixedSizeKeyRefElement, PathKeyElement, PathKeyElementSize, PathKeyRefElement, + PathKeyUnknownElementSize, +}; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use crate::util::object_size_info::PathKeyElementInfo; +use dpp::version::drive_versions::DriveVersion; +use grovedb::{Element, GroveDb, TransactionArg}; + +impl Drive { + /// Inserts a sum item at the specified path and key if it doesn't already exist. + /// If a sum item exists at the specified location and `error_if_exists` is true, an error is returned. + /// If a sum item exists and `error_if_exists` is false, no changes are made. + /// If no sum item exists, a new sum item is inserted at the specified path and key. + /// + /// # Parameters + /// * `path_key_element_info`: Contains information about the path, key, and element to be processed. + /// * `error_if_exists`: A flag that determines whether to return an error if the sum item already exists. + /// * `apply_type`: Defines the type of batch insert to be performed (stateful or stateless). + /// * `transaction`: The transaction argument for the operation. + /// * `drive_operations`: A mutable reference to a vector of low-level drive operations to which new operations will be appended. + /// * `drive_version`: The version of the drive to ensure compatibility with the operation. + /// + /// # Returns + /// * `Ok(())` if the operation is successful. + /// * `Err(Error)` if the operation fails for any reason, such as corrupted state or unsupported operation. + /// + /// # Description + /// This function checks whether an existing sum item exists at the given path and key: + /// - If a sum item is found and `error_if_exists` is true, an error is returned. + /// - If a sum item is found and `error_if_exists` is false, no changes are made. + /// - If no sum item exists, a new sum item is inserted at the specified path and key. + /// + /// This function supports several types of paths and keys, including: + /// - `PathKeyRefElement`: A path with a reference to a key and element. + /// - `PathKeyElement`: A path with a direct key and element. + /// - `PathFixedSizeKeyRefElement`: A fixed-size key reference. + /// - `PathKeyElementSize`: An element with an associated size. + /// - `PathKeyUnknownElementSize`: An unknown element size type. + /// + /// Depending on the element type (`SumItem` in this case), the appropriate operations will be applied. + /// + /// **Note**: Stateful batch insertions of document sizes are not supported. + pub(super) fn batch_insert_sum_item_if_not_exists_v0( + &self, + path_key_element_info: PathKeyElementInfo, + error_if_exists: bool, + apply_type: BatchInsertApplyType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match path_key_element_info { + PathKeyRefElement((path, key, element)) => { + if let Element::SumItem(new_value, _) = element { + // Check if the sum item already exists + let existing_element = self.grove_get_raw_optional( + path.as_slice().into(), + key, + apply_type.to_direct_query_type(), + transaction, + drive_operations, + drive_version, + )?; + + if let Some(Element::SumItem(..)) = existing_element { + if error_if_exists { + return Err(Error::Drive(DriveError::CorruptedDriveState( + "expected no sum item".to_string(), + ))); + } + // Else do nothing + } else if existing_element.is_some() { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected sum item element type", + ))); + } else { + // Insert as a new sum item + drive_operations.push( + LowLevelDriveOperation::insert_for_known_path_key_element( + path, + key.to_vec(), + Element::new_sum_item(new_value), + ), + ); + } + } else { + return Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))); + } + Ok(()) + } + PathKeyElement((path, key, element)) => { + if let Element::SumItem(new_value, _) = element { + // Check if the sum item already exists + let existing_element = self.grove_get_raw_optional( + path.as_slice().into(), + key.as_slice(), + apply_type.to_direct_query_type(), + transaction, + drive_operations, + drive_version, + )?; + + if let Some(Element::SumItem(existing_value, _)) = existing_element { + if error_if_exists { + return Err(Error::Drive(DriveError::CorruptedDriveState( + "expected no sum item".to_string(), + ))); + } + // Else do nothing + } else if existing_element.is_some() { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected sum item element type", + ))); + } else { + // Insert as a new sum item + drive_operations.push( + LowLevelDriveOperation::insert_for_known_path_key_element( + path, + key, + Element::new_sum_item(new_value), + ), + ); + } + } else { + return Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))); + } + Ok(()) + } + PathFixedSizeKeyRefElement((path, key, element)) => { + if let Element::SumItem(new_value, _) = element { + // Check if the sum item already exists + let existing_element = self.grove_get_raw_optional( + path.as_slice().into(), + key, + apply_type.to_direct_query_type(), + transaction, + drive_operations, + drive_version, + )?; + + if let Some(Element::SumItem(existing_value, _)) = existing_element { + if error_if_exists { + return Err(Error::Drive(DriveError::CorruptedDriveState( + "expected no sum item".to_string(), + ))); + } + // Else do nothing + } else if existing_element.is_some() { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected sum item element type", + ))); + } else { + // Insert as a new sum item + let path_items: Vec> = path.into_iter().map(Vec::from).collect(); + drive_operations.push( + LowLevelDriveOperation::insert_for_known_path_key_element( + path_items, + key.to_vec(), + Element::new_sum_item(new_value), + ), + ); + } + } else { + return Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))); + } + Ok(()) + } + PathKeyElementSize((key_info_path, key_info, element)) => { + if let Element::SumItem(new_value, _) = element { + match apply_type { + BatchInsertApplyType::StatelessBatchInsert { + in_tree_using_sums, .. + } => { + // Estimate if the sum item with the given size already exists + drive_operations.push(CalculatedCostOperation( + GroveDb::average_case_for_has_raw( + &key_info_path, + &key_info, + element.serialized_size(&drive_version.grove_version)? as u32, + in_tree_using_sums, + &drive_version.grove_version, + )?, + )); + + drive_operations.push( + LowLevelDriveOperation::insert_for_estimated_path_key_element( + key_info_path, + key_info, + Element::new_sum_item(new_value), + ), + ); + Ok(()) + } + BatchInsertApplyType::StatefulBatchInsert => { + Err(Error::Drive(DriveError::NotSupportedPrivate( + "document sizes for stateful insert in batch operations not supported", + ))) + } + } + } else { + Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))) + } + } + PathKeyUnknownElementSize(_) => Err(Error::Drive(DriveError::NotSupportedPrivate( + "document sizes in batch operations not supported", + ))), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/mod.rs b/packages/rs-drive/src/util/grove_operations/mod.rs index 33f563a9304..119f2d83792 100644 --- a/packages/rs-drive/src/util/grove_operations/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/mod.rs @@ -129,6 +129,8 @@ pub mod grove_get_proved_path_query_with_conditional; /// Inserts an element if it does not exist and returns the existing element if it does in GroveDB. pub mod grove_insert_if_not_exists_return_existing_element; +/// Batch inserts sum items if not already existing +pub mod batch_insert_sum_item_if_not_exists; /// Moved items that are found in a path query to a new path. pub mod batch_move_items_in_path_query; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs index 5197624ade2..ea5387a78b4 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs @@ -12,7 +12,7 @@ pub const DRIVE_CONTRACT_METHOD_VERSIONS_V2: DriveContractMethodVersions = prove_contracts: 0, }, apply: DriveContractApplyMethodVersions { - apply_contract: 0, + apply_contract: 1, // <--- changed to v1 for inserting groups apply_contract_with_serialization: 0, }, insert: DriveContractInsertMethodVersions { diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs new file mode 100644 index 00000000000..4f05d816a12 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs @@ -0,0 +1,26 @@ +use grovedb_version::version::FeatureVersion; + +pub mod v1; + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupMethodVersions { + pub fetch: DriveGroupFetchMethodVersions, + pub prove: DriveGroupProveMethodVersions, + pub insert: DriveGroupInsertMethodVersions, + pub cost_estimation: DriveGroupCostEstimationMethodVersions, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupFetchMethodVersions {} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupProveMethodVersions {} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupInsertMethodVersions { + pub add_new_groups: FeatureVersion, + pub add_group_action: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupCostEstimationMethodVersions {} diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs new file mode 100644 index 00000000000..6b1624dbc4b --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs @@ -0,0 +1,14 @@ +use crate::version::drive_versions::drive_group_method_versions::{ + DriveGroupCostEstimationMethodVersions, DriveGroupFetchMethodVersions, + DriveGroupInsertMethodVersions, DriveGroupMethodVersions, DriveGroupProveMethodVersions, +}; + +pub const DRIVE_GROUP_METHOD_VERSIONS_V1: DriveGroupMethodVersions = DriveGroupMethodVersions { + fetch: DriveGroupFetchMethodVersions {}, + prove: DriveGroupProveMethodVersions {}, + insert: DriveGroupInsertMethodVersions { + add_new_groups: 0, + add_group_action: 0, + }, + cost_estimation: DriveGroupCostEstimationMethodVersions {}, +}; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs index 5118c9093c4..209e0c5d816 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs @@ -40,6 +40,7 @@ pub struct DriveGroveBatchMethodVersions { pub batch_insert_empty_tree: FeatureVersion, pub batch_insert_empty_tree_if_not_exists: FeatureVersion, pub batch_insert_empty_tree_if_not_exists_check_existing_operations: FeatureVersion, + pub batch_insert_sum_item_if_not_exists: FeatureVersion, pub batch_insert_sum_item_or_add_to_if_already_exists: FeatureVersion, pub batch_insert: FeatureVersion, pub batch_insert_if_not_exists: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs index 900a65673dd..7d29de08a6b 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs @@ -31,6 +31,7 @@ pub const DRIVE_GROVE_METHOD_VERSIONS_V1: DriveGroveMethodVersions = DriveGroveM batch_insert_empty_tree: 0, batch_insert_empty_tree_if_not_exists: 0, batch_insert_empty_tree_if_not_exists_check_existing_operations: 0, + batch_insert_sum_item_if_not_exists: 0, batch_insert_sum_item_or_add_to_if_already_exists: 0, batch_insert: 0, batch_insert_if_not_exists: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/mod.rs index a1e68142678..130aa64f5a1 100644 --- a/packages/rs-platform-version/src/version/drive_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/mod.rs @@ -1,12 +1,13 @@ -use crate::version::drive_versions::drive_token_method_versions::DriveTokenMethodVersions; use crate::version::FeatureVersion; use drive_contract_method_versions::DriveContractMethodVersions; use drive_credit_pool_method_versions::DriveCreditPoolMethodVersions; use drive_document_method_versions::DriveDocumentMethodVersions; +use drive_group_method_versions::DriveGroupMethodVersions; use drive_grove_method_versions::DriveGroveMethodVersions; use drive_identity_method_versions::DriveIdentityMethodVersions; use drive_state_transition_method_versions::DriveStateTransitionMethodVersions; use drive_structure_version::DriveStructureVersion; +use drive_token_method_versions::DriveTokenMethodVersions; use drive_verify_method_versions::DriveVerifyMethodVersions; use drive_vote_method_versions::DriveVoteMethodVersions; use grovedb_version::version::GroveVersion; @@ -14,6 +15,7 @@ use grovedb_version::version::GroveVersion; pub mod drive_contract_method_versions; pub mod drive_credit_pool_method_versions; pub mod drive_document_method_versions; +pub mod drive_group_method_versions; pub mod drive_grove_method_versions; pub mod drive_identity_method_versions; pub mod drive_state_transition_method_versions; @@ -56,6 +58,7 @@ pub struct DriveMethodVersions { pub prove: DriveProveMethodVersions, pub state_transitions: DriveStateTransitionMethodVersions, pub platform_state: DrivePlatformStateMethodVersions, + pub group: DriveGroupMethodVersions, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/v1.rs index b058e036701..6fd8d42f987 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v1.rs @@ -1,6 +1,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; @@ -96,6 +97,7 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/v2.rs index 9ffd2082845..62cd996763d 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v2.rs @@ -1,6 +1,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; @@ -96,6 +97,7 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v3.rs b/packages/rs-platform-version/src/version/drive_versions/v3.rs index 30d67ebfd7d..f7e8b1b1e78 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v3.rs @@ -1,6 +1,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CONTRACT_METHOD_VERSIONS_V2; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; @@ -96,6 +97,7 @@ pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index 66f624b692d..88f8ad14365 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -27,6 +27,7 @@ use crate::version::drive_abci_versions::DriveAbciVersion; use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; @@ -131,6 +132,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1,