diff --git a/Cargo.lock b/Cargo.lock index 5964aaa3fb..f55e79caa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2099,7 +2099,7 @@ dependencies = [ [[package]] name = "grovedb" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "axum", "bincode", @@ -2130,7 +2130,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "integer-encoding", "intmap", @@ -2140,7 +2140,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "grovedb-costs", "hex", @@ -2152,7 +2152,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "bincode", "blake3", @@ -2175,7 +2175,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "hex", ] @@ -2183,7 +2183,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "blake3", "grovedb-costs", @@ -2202,7 +2202,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "thiserror 2.0.11", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2211,7 +2211,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "hex", "itertools 0.14.0", @@ -2220,7 +2220,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" +source = "git+https://github.com/dashpay/grovedb?rev=44c2244bbccd3e6e684729e8cf620644f7ebbf70#44c2244bbccd3e6e684729e8cf620644f7ebbf70" dependencies = [ "serde", "serde_with 3.9.0", diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 44d27fc8be..a071a3174b 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -1622,6 +1622,12 @@ message GetGroupActionsResponse { optional string public_note = 2; // Public note } + // Token config update event + message TokenConfigUpdateEvent { + bytes token_config_update_item = 1; // Token config update item + optional string public_note = 2; // Public note + } + // Event associated with this action message GroupActionEvent { oneof event_type { @@ -1661,6 +1667,7 @@ message GetGroupActionsResponse { DestroyFrozenFundsEvent destroy_frozen_funds = 5; // Destroy frozen funds TransferEvent transfer = 6; // Transfer event details EmergencyActionEvent emergency_action = 7; // Emergency action details + TokenConfigUpdateEvent token_config_update = 8; // Token configuration update details } } diff --git a/packages/rs-dpp/src/data_contract/associated_token/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/mod.rs index ad9156e391..d7558c24b1 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/mod.rs @@ -1 +1,3 @@ pub mod token_configuration; +pub mod token_configuration_convention; +pub mod token_configuration_item; diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs index 46c82e7995..31e816a0b1 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs @@ -1,33 +1,41 @@ pub mod v0; +use crate::balances::credits::TokenAmount; use crate::data_contract::associated_token::token_configuration::accessors::v0::{ TokenConfigurationV0Getters, TokenConfigurationV0Setters, }; -use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationConventionV0; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::ChangeControlRules; use crate::data_contract::GroupContractPosition; use platform_value::Identifier; +use std::collections::BTreeSet; /// Implementing TokenConfigurationV0Getters for TokenConfiguration impl TokenConfigurationV0Getters for TokenConfiguration { /// Returns a reference to the conventions. - fn conventions(&self) -> &TokenConfigurationConventionV0 { + fn conventions(&self) -> &TokenConfigurationConvention { match self { TokenConfiguration::V0(v0) => v0.conventions(), } } /// Returns a mutable reference to the conventions. - fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0 { + fn conventions_mut(&mut self) -> &mut TokenConfigurationConvention { match self { TokenConfiguration::V0(v0) => v0.conventions_mut(), } } + fn conventions_change_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.conventions_change_rules(), + } + } + /// Returns the base supply. - fn base_supply(&self) -> u64 { + fn base_supply(&self) -> TokenAmount { match self { TokenConfiguration::V0(v0) => v0.base_supply(), } @@ -141,17 +149,31 @@ impl TokenConfigurationV0Getters for TokenConfiguration { TokenConfiguration::V0(v0) => v0.main_control_group_can_be_modified(), } } + + /// Returns all group positions used in the token configuration + fn all_used_group_positions(&self) -> BTreeSet { + match self { + TokenConfiguration::V0(v0) => v0.all_used_group_positions(), + } + } } /// Implementing TokenConfigurationV0Setters for TokenConfiguration impl TokenConfigurationV0Setters for TokenConfiguration { /// Sets the conventions. - fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0) { + fn set_conventions(&mut self, conventions: TokenConfigurationConvention) { match self { TokenConfiguration::V0(v0) => v0.set_conventions(conventions), } } + /// Sets the conventions change rules. + fn set_conventions_change_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_conventions_change_rules(rules), + } + } + /// Sets the base supply. fn set_base_supply(&mut self, base_supply: u64) { match self { 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 cc1de8cb81..b1b4143059 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,17 +1,20 @@ use crate::balances::credits::TokenAmount; -use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationConventionV0; +use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::ChangeControlRules; use crate::data_contract::GroupContractPosition; use platform_value::Identifier; +use std::collections::BTreeSet; /// Accessor trait for getters of `TokenConfigurationV0` pub trait TokenConfigurationV0Getters { /// Returns a reference to the conventions. - fn conventions(&self) -> &TokenConfigurationConventionV0; + fn conventions(&self) -> &TokenConfigurationConvention; /// Returns a mutable reference to the conventions. - fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0; + fn conventions_mut(&mut self) -> &mut TokenConfigurationConvention; + /// Returns the new tokens destination identity rules. + fn conventions_change_rules(&self) -> &ChangeControlRules; /// Returns the base supply. fn base_supply(&self) -> TokenAmount; @@ -56,12 +59,18 @@ pub trait TokenConfigurationV0Getters { /// Returns the main control group can be modified. fn main_control_group_can_be_modified(&self) -> &AuthorizedActionTakers; + + /// Returns all group positions used in the token configuration + fn all_used_group_positions(&self) -> BTreeSet; } /// Accessor trait for setters of `TokenConfigurationV0` pub trait TokenConfigurationV0Setters { /// Sets the conventions. - fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0); + fn set_conventions(&mut self, conventions: TokenConfigurationConvention); + + /// Sets the conventions change rules. + fn set_conventions_change_rules(&mut self, rules: ChangeControlRules); /// Sets the base supply. fn set_base_supply(&mut self, base_supply: TokenAmount); diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/apply_token_configuration_item/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/apply_token_configuration_item/mod.rs new file mode 100644 index 0000000000..9468c91ca7 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/apply_token_configuration_item/mod.rs @@ -0,0 +1,18 @@ +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; + +mod v0; + +impl TokenConfiguration { + /// Applies a `TokenConfigurationChangeItem` to this token configuration. + /// + /// # Parameters + /// - `change_item`: The change item to be applied. + /// + /// This method modifies the current `TokenConfigurationV0` instance in place. + pub fn apply_token_configuration_item(&mut self, change_item: TokenConfigurationChangeItem) { + match self { + TokenConfiguration::V0(v0) => v0.apply_token_configuration_item(change_item), + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/apply_token_configuration_item/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/apply_token_configuration_item/v0/mod.rs new file mode 100644 index 0000000000..706faf5f48 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/apply_token_configuration_item/v0/mod.rs @@ -0,0 +1,116 @@ +use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +impl TokenConfigurationV0 { + /// Applies a `TokenConfigurationChangeItem` to this token configuration. + /// + /// # Parameters + /// - `change_item`: The change item to be applied. + /// + /// This method modifies the current `TokenConfigurationV0` instance in place. + pub fn apply_token_configuration_item(&mut self, change_item: TokenConfigurationChangeItem) { + match change_item { + TokenConfigurationChangeItem::TokenConfigurationNoChange => { + // No changes are made + } + TokenConfigurationChangeItem::Conventions(conventions) => { + self.conventions = conventions; + } + TokenConfigurationChangeItem::ConventionsControlGroup(control_group) => { + self.conventions_change_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::ConventionsAdminGroup(admin_group) => { + self.conventions_change_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::MaxSupply(max_supply) => { + self.max_supply = max_supply; + } + TokenConfigurationChangeItem::MaxSupplyControlGroup(control_group) => { + self.max_supply_change_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::MaxSupplyAdminGroup(admin_group) => { + self.max_supply_change_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::NewTokensDestinationIdentity(identity) => { + self.new_tokens_destination_identity = identity; + } + TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup( + control_group, + ) => { + self.new_tokens_destination_identity_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(admin_group) => { + self.new_tokens_destination_identity_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::MintingAllowChoosingDestination(allow) => { + self.minting_allow_choosing_destination = allow; + } + TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup( + control_group, + ) => { + self.minting_allow_choosing_destination_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup( + admin_group, + ) => { + self.minting_allow_choosing_destination_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::ManualMinting(control_group) => { + self.manual_minting_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::ManualMintingAdminGroup(admin_group) => { + self.manual_minting_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::ManualBurning(control_group) => { + self.manual_burning_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::ManualBurningAdminGroup(admin_group) => { + self.manual_burning_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::Freeze(control_group) => { + self.freeze_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::FreezeAdminGroup(admin_group) => { + self.freeze_rules.set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::Unfreeze(control_group) => { + self.unfreeze_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::UnfreezeAdminGroup(admin_group) => { + self.unfreeze_rules.set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::DestroyFrozenFunds(control_group) => { + self.destroy_frozen_funds_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(admin_group) => { + self.destroy_frozen_funds_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::EmergencyAction(control_group) => { + self.emergency_action_rules + .set_authorized_to_make_change_action_takers(control_group); + } + TokenConfigurationChangeItem::EmergencyActionAdminGroup(admin_group) => { + self.emergency_action_rules + .set_admin_action_takers(admin_group); + } + TokenConfigurationChangeItem::MainControlGroup(main_group) => { + self.main_control_group = main_group; + } + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/authorized_action_takers_for_configuration_item/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/authorized_action_takers_for_configuration_item/mod.rs new file mode 100644 index 0000000000..3a52cff129 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/authorized_action_takers_for_configuration_item/mod.rs @@ -0,0 +1,25 @@ +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; + +mod v0; + +impl TokenConfiguration { + /// Returns the authorized action takers for a specific `TokenConfigurationChangeItem`. + /// + /// # Parameters + /// - `change_item`: The change item for which to retrieve the authorized action takers. + /// + /// # Returns + /// - `AuthorizedActionTakers`: The authorized action takers for the given change item. + pub fn authorized_action_takers_for_configuration_item( + &self, + change_item: &TokenConfigurationChangeItem, + ) -> AuthorizedActionTakers { + match self { + TokenConfiguration::V0(v0) => { + v0.authorized_action_takers_for_configuration_item(change_item) + } + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/authorized_action_takers_for_configuration_item/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/authorized_action_takers_for_configuration_item/v0/mod.rs new file mode 100644 index 0000000000..bf8d070994 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/authorized_action_takers_for_configuration_item/v0/mod.rs @@ -0,0 +1,112 @@ +use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +impl TokenConfigurationV0 { + /// Returns the authorized action takers for a specific `TokenConfigurationChangeItem`. + /// + /// # Parameters + /// - `change_item`: The change item for which to retrieve the authorized action takers. + /// + /// # Returns + /// - `AuthorizedActionTakers`: The authorized action takers for the given change item. + pub fn authorized_action_takers_for_configuration_item( + &self, + change_item: &TokenConfigurationChangeItem, + ) -> AuthorizedActionTakers { + match change_item { + TokenConfigurationChangeItem::TokenConfigurationNoChange => { + AuthorizedActionTakers::NoOne + } + TokenConfigurationChangeItem::Conventions(_) => self + .conventions_change_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::ConventionsControlGroup(_) => self + .conventions_change_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::ConventionsAdminGroup(_) => { + self.conventions_change_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::MaxSupply(_) => self + .max_supply_change_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::MaxSupplyControlGroup(_) => self + .max_supply_change_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::MaxSupplyAdminGroup(_) => { + self.max_supply_change_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::NewTokensDestinationIdentity(_) => self + .new_tokens_destination_identity_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(_) => self + .new_tokens_destination_identity_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(_) => self + .new_tokens_destination_identity_rules + .admin_action_takers() + .clone(), + TokenConfigurationChangeItem::MintingAllowChoosingDestination(_) => self + .minting_allow_choosing_destination_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(_) => self + .minting_allow_choosing_destination_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(_) => self + .minting_allow_choosing_destination_rules + .admin_action_takers() + .clone(), + TokenConfigurationChangeItem::ManualMinting(_) => self + .manual_minting_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::ManualMintingAdminGroup(_) => { + self.manual_minting_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::ManualBurning(_) => self + .manual_burning_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::ManualBurningAdminGroup(_) => { + self.manual_burning_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::Freeze(_) => self + .freeze_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::FreezeAdminGroup(_) => { + self.freeze_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::Unfreeze(_) => self + .unfreeze_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::UnfreezeAdminGroup(_) => { + self.unfreeze_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::DestroyFrozenFunds(_) => self + .destroy_frozen_funds_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(_) => self + .destroy_frozen_funds_rules + .admin_action_takers() + .clone(), + TokenConfigurationChangeItem::EmergencyAction(_) => self + .emergency_action_rules + .authorized_to_make_change_action_takers() + .clone(), + TokenConfigurationChangeItem::EmergencyActionAdminGroup(_) => { + self.emergency_action_rules.admin_action_takers().clone() + } + TokenConfigurationChangeItem::MainControlGroup(_) => AuthorizedActionTakers::NoOne, + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/can_apply_token_configuration_item/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/can_apply_token_configuration_item/mod.rs new file mode 100644 index 0000000000..8aa4d41a4b --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/can_apply_token_configuration_item/mod.rs @@ -0,0 +1,38 @@ +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use crate::data_contract::group::Group; +use crate::data_contract::GroupContractPosition; +use crate::group::action_taker::{ActionGoal, ActionTaker}; +use platform_value::Identifier; +use std::collections::BTreeMap; + +mod v0; + +impl TokenConfiguration { + /// Applies a `TokenConfigurationChangeItem` to this token configuration. + /// + /// # Parameters + /// - `change_item`: The change item to be applied. + /// + /// This method modifies the current `TokenConfigurationV0` instance in place. + pub fn can_apply_token_configuration_item( + &self, + change_item: &TokenConfigurationChangeItem, + contract_owner_id: &Identifier, + main_group: Option, + groups: &BTreeMap, + action_taker: &ActionTaker, + goal: ActionGoal, + ) -> bool { + match self { + TokenConfiguration::V0(v0) => v0.can_apply_token_configuration_item( + change_item, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/can_apply_token_configuration_item/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/can_apply_token_configuration_item/v0/mod.rs new file mode 100644 index 0000000000..158143efa0 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/can_apply_token_configuration_item/v0/mod.rs @@ -0,0 +1,253 @@ +use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use crate::data_contract::group::Group; +use crate::data_contract::GroupContractPosition; +use crate::group::action_taker::{ActionGoal, ActionTaker}; +use platform_value::Identifier; +use std::collections::BTreeMap; +impl TokenConfigurationV0 { + /// Determines whether a `TokenConfigurationChangeItem` can be applied to this token configuration. + /// + /// # Parameters + /// - `change_item`: The change item to evaluate. + /// - `contract_owner_id`: The ID of the contract owner. + /// - `main_group`: The main control group position, if any. + /// - `groups`: A map of group positions to their respective `Group` instances. + /// - `action_taker`: The entity attempting the action. + /// - `goal`: The goal of the action being attempted. + /// + /// Returns `true` if the change item can be applied, `false` otherwise. + pub fn can_apply_token_configuration_item( + &self, + change_item: &TokenConfigurationChangeItem, + contract_owner_id: &Identifier, + main_group: Option, + groups: &BTreeMap, + action_taker: &ActionTaker, + goal: ActionGoal, + ) -> bool { + match change_item { + TokenConfigurationChangeItem::TokenConfigurationNoChange => false, + TokenConfigurationChangeItem::Conventions(_) => self + .conventions_change_rules + .can_make_change(contract_owner_id, main_group, groups, action_taker, goal), + TokenConfigurationChangeItem::ConventionsControlGroup(control_group) => self + .conventions_change_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::ConventionsAdminGroup(admin_group) => self + .conventions_change_rules + .can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::MaxSupply(_) => self + .max_supply_change_rules + .can_make_change(contract_owner_id, main_group, groups, action_taker, goal), + TokenConfigurationChangeItem::MaxSupplyControlGroup(control_group) => self + .max_supply_change_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::MaxSupplyAdminGroup(admin_group) => { + self.max_supply_change_rules.can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::NewTokensDestinationIdentity(_) => self + .new_tokens_destination_identity_rules + .can_make_change(contract_owner_id, main_group, groups, action_taker, goal), + TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup( + control_group, + ) => self + .new_tokens_destination_identity_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(admin_group) => { + self.new_tokens_destination_identity_rules + .can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::MintingAllowChoosingDestination(_) => self + .minting_allow_choosing_destination_rules + .can_make_change(contract_owner_id, main_group, groups, action_taker, goal), + TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup( + control_group, + ) => self + .minting_allow_choosing_destination_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup( + admin_group, + ) => self + .minting_allow_choosing_destination_rules + .can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::ManualMinting(control_group) => self + .manual_minting_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::ManualMintingAdminGroup(admin_group) => { + self.manual_minting_rules.can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::ManualBurning(control_group) => self + .manual_burning_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::ManualBurningAdminGroup(admin_group) => { + self.manual_burning_rules.can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::Freeze(control_group) => { + self.freeze_rules.can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::FreezeAdminGroup(admin_group) => { + self.freeze_rules.can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::Unfreeze(control_group) => { + self.unfreeze_rules.can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::UnfreezeAdminGroup(admin_group) => { + self.unfreeze_rules.can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::DestroyFrozenFunds(control_group) => self + .destroy_frozen_funds_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(admin_group) => self + .destroy_frozen_funds_rules + .can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::EmergencyAction(control_group) => self + .emergency_action_rules + .can_change_authorized_action_takers( + control_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + TokenConfigurationChangeItem::EmergencyActionAdminGroup(admin_group) => { + self.emergency_action_rules.can_change_admin_action_takers( + admin_group, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + TokenConfigurationChangeItem::MainControlGroup(_) => false, // Main control group cannot be updated directly + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/mod.rs index 5e5a7181a5..85a371e739 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/mod.rs @@ -1 +1,5 @@ +mod apply_token_configuration_item; +mod authorized_action_takers_for_configuration_item; +mod can_apply_token_configuration_item; +mod validate_token_configuration_groups_exist; mod validate_token_configuration_update; diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/mod.rs new file mode 100644 index 0000000000..d4d5d285fe --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/mod.rs @@ -0,0 +1,50 @@ +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::group::Group; +use crate::data_contract::GroupContractPosition; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +mod v0; + +impl TokenConfiguration { + /// Validates that all group positions referenced in the token configuration exist in the provided groups map. + /// + /// # Parameters + /// - `groups`: A reference to a `BTreeMap` containing group positions as keys and their associated `Group` objects as values. + /// These represent the groups defined in the data contract. + /// - `platform_version`: A reference to the `PlatformVersion` object specifying the version of the function to call. + /// + /// # Returns + /// - `Ok(SimpleConsensusValidationResult)`: If the validation is successful, returns a result containing a validation result object, + /// which will be empty if no errors are found. + /// - `Err(ProtocolError)`: If an unknown or unsupported platform version is specified, an error indicating a version mismatch is returned. + /// + /// # Errors + /// - If a group position referenced in the token configuration does not exist in the provided `groups` map, the method will invoke the + /// version-specific validation logic, which will include any corresponding validation errors. + /// + /// # Versioning + /// - This function dispatches to version-specific validation logic based on the `platform_version`. + /// - Currently supports `validate_token_config_groups_exist_v0` for version `0`. + pub fn validate_token_config_groups_exist( + &self, + groups: &BTreeMap, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .validation + .data_contract + .validate_token_config_groups_exist + { + 0 => Ok(self.validate_token_config_groups_exist_v0(groups)), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "validate_token_config_groups_exist".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/v0/mod.rs new file mode 100644 index 0000000000..e49571e07e --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/v0/mod.rs @@ -0,0 +1,42 @@ +use crate::consensus::basic::data_contract::GroupPositionDoesNotExistError; +use crate::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::group::Group; +use crate::data_contract::GroupContractPosition; +use crate::validation::SimpleConsensusValidationResult; +use std::collections::BTreeMap; + +impl TokenConfiguration { + #[inline(always)] + pub(super) fn validate_token_config_groups_exist_v0( + &self, + groups: &BTreeMap, + ) -> SimpleConsensusValidationResult { + // Initialize validation result + let validation_result = SimpleConsensusValidationResult::new(); + + // Collect all group positions used in the token configuration + let group_positions = self.all_used_group_positions(); + + // Check that all referenced group positions exist in the provided groups map + for group_position in group_positions { + if !groups.contains_key(&group_position) { + return SimpleConsensusValidationResult::new_with_error( + GroupPositionDoesNotExistError::new(group_position).into(), + ); + } + } + + // If a main group is defined in the token configuration, verify its existence + if let Some(main_group_position) = self.main_control_group() { + if !groups.contains_key(&main_group_position) { + return SimpleConsensusValidationResult::new_with_error( + GroupPositionDoesNotExistError::new(main_group_position).into(), + ); + } + } + + // If we reach here with no errors, return an empty result + validation_result + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/mod.rs index 9dda53c984..a0a12019fb 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/mod.rs @@ -1,7 +1,7 @@ use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::group::Group; use crate::data_contract::GroupContractPosition; -use crate::multi_identity_events::ActionTaker; +use crate::group::action_taker::{ActionGoal, ActionTaker}; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; use platform_value::Identifier; @@ -15,9 +15,9 @@ impl TokenConfiguration { &self, new_config: &TokenConfiguration, contract_owner_id: &Identifier, - main_group: Option<&Group>, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -29,9 +29,9 @@ impl TokenConfiguration { 0 => Ok(self.validate_token_config_update_v0( new_config, contract_owner_id, - main_group, groups, action_taker, + goal, )), version => Err(ProtocolError::UnknownVersionMismatch { method: "validate_token_config_update".to_string(), diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs index a11f775a57..9789261865 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs @@ -1,8 +1,9 @@ use crate::consensus::basic::data_contract::DataContractTokenConfigurationUpdateError; +use crate::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::group::Group; use crate::data_contract::GroupContractPosition; -use crate::multi_identity_events::ActionTaker; +use crate::group::action_taker::{ActionGoal, ActionTaker}; use crate::validation::SimpleConsensusValidationResult; use platform_value::Identifier; use std::collections::BTreeMap; @@ -13,24 +14,35 @@ impl TokenConfiguration { &self, new_config: &TokenConfiguration, contract_owner_id: &Identifier, - main_group: Option<&Group>, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, ) -> SimpleConsensusValidationResult { let old = self.as_cow_v0(); let new = new_config.as_cow_v0(); // Check immutable fields: conventions - if old.conventions != new.conventions { - return SimpleConsensusValidationResult::new_with_error( - DataContractTokenConfigurationUpdateError::new( - "update".to_string(), - "conventions".to_string(), - self.clone(), - new_config.clone(), - ) - .into(), - ); + if old.conventions != new.conventions + || old.conventions_change_rules != new.conventions_change_rules + { + if !old.conventions_change_rules.can_change_to( + &new.conventions_change_rules, + contract_owner_id, + self.main_control_group(), + groups, + action_taker, + goal, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "conventions or conventionsRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } } // Check immutable fields: base_supply @@ -53,9 +65,10 @@ impl TokenConfiguration { if !old.max_supply_change_rules.can_change_to( &new.max_supply_change_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -77,9 +90,10 @@ impl TokenConfiguration { if !old.new_tokens_destination_identity_rules.can_change_to( &new.new_tokens_destination_identity_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -102,9 +116,10 @@ impl TokenConfiguration { if !old.minting_allow_choosing_destination_rules.can_change_to( &new.minting_allow_choosing_destination_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -124,9 +139,10 @@ impl TokenConfiguration { if !old.manual_minting_rules.can_change_to( &new.manual_minting_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -145,9 +161,10 @@ impl TokenConfiguration { if !old.manual_burning_rules.can_change_to( &new.manual_burning_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -166,9 +183,10 @@ impl TokenConfiguration { if !old.freeze_rules.can_change_to( &new.freeze_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -187,9 +205,10 @@ impl TokenConfiguration { if !old.unfreeze_rules.can_change_to( &new.unfreeze_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -208,9 +227,10 @@ impl TokenConfiguration { if !old.destroy_frozen_funds_rules.can_change_to( &new.destroy_frozen_funds_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -229,9 +249,10 @@ impl TokenConfiguration { if !old.emergency_action_rules.can_change_to( &new.emergency_action_rules, contract_owner_id, - main_group, + self.main_control_group(), groups, action_taker, + goal, ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( @@ -249,7 +270,13 @@ impl TokenConfiguration { if old.main_control_group != new.main_control_group { if !old .main_control_group_can_be_modified - .allowed_for_action_taker(contract_owner_id, main_group, groups, action_taker) + .allowed_for_action_taker( + contract_owner_id, + self.main_control_group(), + groups, + action_taker, + goal, + ) { return SimpleConsensusValidationResult::new_with_error( DataContractTokenConfigurationUpdateError::new( diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs index 60312bd445..3d4642ab8d 100644 --- a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs @@ -3,25 +3,31 @@ use crate::data_contract::associated_token::token_configuration::accessors::v0:: TokenConfigurationV0Getters, TokenConfigurationV0Setters, }; use crate::data_contract::associated_token::token_configuration::v0::{ - TokenConfigurationConventionV0, TokenConfigurationV0, + TokenConfigurationConvention, TokenConfigurationV0, }; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::ChangeControlRules; use crate::data_contract::GroupContractPosition; use platform_value::Identifier; +use std::collections::BTreeSet; /// Implementing `TokenConfigurationV0Getters` for `TokenConfigurationV0` impl TokenConfigurationV0Getters for TokenConfigurationV0 { /// Returns a reference to the conventions. - fn conventions(&self) -> &TokenConfigurationConventionV0 { + fn conventions(&self) -> &TokenConfigurationConvention { &self.conventions } /// Returns a mutable reference to the conventions. - fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0 { + fn conventions_mut(&mut self) -> &mut TokenConfigurationConvention { &mut self.conventions } + /// Returns the conventions change rules. + fn conventions_change_rules(&self) -> &ChangeControlRules { + &self.conventions_change_rules + } + /// Returns the base supply. fn base_supply(&self) -> TokenAmount { self.base_supply @@ -106,15 +112,60 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 { fn main_control_group_can_be_modified(&self) -> &AuthorizedActionTakers { &self.main_control_group_can_be_modified } + + /// Returns all group positions used in the token configuration + fn all_used_group_positions(&self) -> BTreeSet { + let mut group_positions = BTreeSet::new(); + + // Add the main control group if it exists + if let Some(main_group_position) = self.main_control_group { + group_positions.insert(main_group_position); + } + + // Helper function to extract group positions from `AuthorizedActionTakers` + let mut add_from_authorized_action_takers = |authorized_takers: &AuthorizedActionTakers| { + if let AuthorizedActionTakers::Group(group_position) = authorized_takers { + group_positions.insert(*group_position); + } + }; + + // Add positions from change control rules + let mut add_from_change_control_rules = |rules: &ChangeControlRules| { + add_from_authorized_action_takers(rules.authorized_to_make_change_action_takers()); + add_from_authorized_action_takers(rules.admin_action_takers()); + }; + + // Apply the helper to all fields containing `ChangeControlRules` + add_from_change_control_rules(&self.max_supply_change_rules); + add_from_change_control_rules(&self.conventions_change_rules); + add_from_change_control_rules(&self.new_tokens_destination_identity_rules); + add_from_change_control_rules(&self.minting_allow_choosing_destination_rules); + add_from_change_control_rules(&self.manual_minting_rules); + add_from_change_control_rules(&self.manual_burning_rules); + add_from_change_control_rules(&self.freeze_rules); + add_from_change_control_rules(&self.unfreeze_rules); + add_from_change_control_rules(&self.destroy_frozen_funds_rules); + add_from_change_control_rules(&self.emergency_action_rules); + + // Add positions from the `main_control_group_can_be_modified` field + add_from_authorized_action_takers(&self.main_control_group_can_be_modified); + + group_positions + } } /// Implementing `TokenConfigurationV0Setters` for `TokenConfigurationV0` impl TokenConfigurationV0Setters for TokenConfigurationV0 { /// Sets the conventions. - fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0) { + fn set_conventions(&mut self, conventions: TokenConfigurationConvention) { self.conventions = conventions; } + /// Sets the new conventions change rules. + fn set_conventions_change_rules(&mut self, rules: ChangeControlRules) { + self.conventions_change_rules = rules; + } + /// Sets the base supply. fn set_base_supply(&mut self, base_supply: TokenAmount) { self.base_supply = base_supply; 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 a192c4ab43..6f6bcd9556 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 @@ -1,6 +1,8 @@ mod accessors; use crate::balances::credits::TokenAmount; +use crate::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0; +use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention; use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::change_control_rules::v0::ChangeControlRulesV0; use crate::data_contract::change_control_rules::ChangeControlRules; @@ -8,35 +10,15 @@ use crate::data_contract::GroupContractPosition; use bincode::{Decode, Encode}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; use std::fmt; -#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct TokenConfigurationLocalizationsV0 { - pub should_capitalize: bool, - pub singular_form: String, - pub plural_form: String, -} - -#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, Default)] -#[serde(rename_all = "camelCase")] -pub struct TokenConfigurationConventionV0 { - #[serde(default)] - pub localizations: BTreeMap, - #[serde(default = "default_decimals")] - pub decimals: u16, -} - -// Default function for `decimals` -fn default_decimals() -> u16 { - 8 // Default value for decimals -} - #[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct TokenConfigurationV0 { - pub conventions: TokenConfigurationConventionV0, + pub conventions: TokenConfigurationConvention, + /// Who can change the conventions + #[serde(default = "default_change_control_rules")] + pub conventions_change_rules: ChangeControlRules, /// The supply at the creation of the token pub base_supply: TokenAmount, /// The maximum supply the token can ever have @@ -96,18 +78,20 @@ fn default_starts_as_paused() -> bool { fn default_change_control_rules() -> ChangeControlRules { ChangeControlRules::V0(ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }) } fn default_contract_owner_change_control_rules() -> ChangeControlRules { ChangeControlRules::V0(ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::ContractOwner, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }) } @@ -115,8 +99,9 @@ impl fmt::Display for TokenConfigurationV0 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "TokenConfigurationV0 {{\n conventions: {:?},\n base_supply: {},\n max_supply: {:?},\n keeps_history: {},\n start_as_paused: {},\n max_supply_change_rules: {:?},\n new_tokens_destination_identity: {:?},\n new_tokens_destination_identity_rules: {:?},\n minting_allow_choosing_destination: {},\n minting_allow_choosing_destination_rules: {:?},\n manual_minting_rules: {:?},\n manual_burning_rules: {:?},\n freeze_rules: {:?},\n unfreeze_rules: {:?},\n destroy_frozen_funds_rules: {:?},\n emergency_action_rules: {:?},\n main_control_group: {:?},\n main_control_group_can_be_modified: {:?}\n}}", + "TokenConfigurationV0 {{\n conventions: {:?},\n conventions_change_rules: {:?},\n base_supply: {},\n max_supply: {:?},\n keeps_history: {},\n start_as_paused: {},\n max_supply_change_rules: {:?},\n new_tokens_destination_identity: {:?},\n new_tokens_destination_identity_rules: {:?},\n minting_allow_choosing_destination: {},\n minting_allow_choosing_destination_rules: {:?},\n manual_minting_rules: {:?},\n manual_burning_rules: {:?},\n freeze_rules: {:?},\n unfreeze_rules: {:?},\n destroy_frozen_funds_rules: {:?},\n emergency_action_rules: {:?},\n main_control_group: {:?},\n main_control_group_can_be_modified: {:?}\n}}", self.conventions, + self.conventions_change_rules, self.base_supply, self.max_supply, self.keeps_history, @@ -141,77 +126,94 @@ impl fmt::Display for TokenConfigurationV0 { impl TokenConfigurationV0 { pub fn default_most_restrictive() -> Self { Self { - conventions: TokenConfigurationConventionV0 { + conventions: TokenConfigurationConvention::V0(TokenConfigurationConventionV0 { localizations: Default::default(), decimals: 8, - }, + }), + conventions_change_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + } + .into(), base_supply: 100000, max_supply: None, keeps_history: true, start_as_paused: false, max_supply_change_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), new_tokens_destination_identity: None, new_tokens_destination_identity_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), minting_allow_choosing_destination: true, minting_allow_choosing_destination_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), manual_minting_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), manual_burning_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), freeze_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), unfreeze_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), destroy_frozen_funds_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), emergency_action_rules: ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, } .into(), main_control_group: None, diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration_convention/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration_convention/mod.rs new file mode 100644 index 0000000000..76a4ed1370 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration_convention/mod.rs @@ -0,0 +1,25 @@ +use crate::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0; +use bincode::{Decode, Encode}; +use derive_more::From; +use serde::{Deserialize, Serialize}; + +pub mod v0; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, Clone, PartialEq, Eq, PartialOrd, From)] +#[serde(tag = "$format_version")] +pub enum TokenConfigurationConvention { + #[serde(rename = "0")] + V0(TokenConfigurationConventionV0), +} + +use std::fmt; + +impl fmt::Display for TokenConfigurationConvention { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenConfigurationConvention::V0(v0) => { + write!(f, "{}", v0) //just pass through + } + } + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration_convention/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration_convention/v0/mod.rs new file mode 100644 index 0000000000..6ea538cc6e --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration_convention/v0/mod.rs @@ -0,0 +1,56 @@ +use bincode::Encode; +use platform_serialization::de::Decode; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fmt; + +#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd)] +#[serde(rename_all = "camelCase")] +pub struct TokenConfigurationLocalizationsV0 { + pub should_capitalize: bool, + pub singular_form: String, + pub plural_form: String, +} + +impl fmt::Display for TokenConfigurationLocalizationsV0 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Capitalized: {}, Singular: '{}', Plural: '{}'", + self.should_capitalize, self.singular_form, self.plural_form + ) + } +} + +#[derive( + Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd, Default, +)] +#[serde(rename_all = "camelCase")] +pub struct TokenConfigurationConventionV0 { + #[serde(default)] + pub localizations: BTreeMap, + #[serde(default = "default_decimals")] + pub decimals: u16, +} + +// Default function for `decimals` +fn default_decimals() -> u16 { + 8 // Default value for decimals +} + +impl fmt::Display for TokenConfigurationConventionV0 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let localizations: Vec = self + .localizations + .iter() + .map(|(key, value)| format!("{}: {}", key, value)) + .collect(); + + write!( + f, + "Decimals: {}, Localizations: [{}]", + self.decimals, + localizations.join(", ") + ) + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration_item.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration_item.rs new file mode 100644 index 0000000000..12c32c83be --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration_item.rs @@ -0,0 +1,203 @@ +use crate::balances::credits::TokenAmount; +use crate::data_contract::associated_token::token_configuration_convention::TokenConfigurationConvention; +use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +use crate::data_contract::GroupContractPosition; +use crate::ProtocolError; +use bincode::Encode; +use platform_serialization::de::Decode; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive( + Debug, + Clone, + Default, + PartialOrd, + Encode, + Decode, + PlatformSerialize, + PlatformDeserialize, + PartialEq, + Eq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub enum TokenConfigurationChangeItem { + #[default] + TokenConfigurationNoChange, + Conventions(TokenConfigurationConvention), + ConventionsControlGroup(AuthorizedActionTakers), + ConventionsAdminGroup(AuthorizedActionTakers), + MaxSupply(Option), + MaxSupplyControlGroup(AuthorizedActionTakers), + MaxSupplyAdminGroup(AuthorizedActionTakers), + NewTokensDestinationIdentity(Option), + NewTokensDestinationIdentityControlGroup(AuthorizedActionTakers), + NewTokensDestinationIdentityAdminGroup(AuthorizedActionTakers), + MintingAllowChoosingDestination(bool), + MintingAllowChoosingDestinationControlGroup(AuthorizedActionTakers), + MintingAllowChoosingDestinationAdminGroup(AuthorizedActionTakers), + ManualMinting(AuthorizedActionTakers), + ManualMintingAdminGroup(AuthorizedActionTakers), + ManualBurning(AuthorizedActionTakers), + ManualBurningAdminGroup(AuthorizedActionTakers), + Freeze(AuthorizedActionTakers), + FreezeAdminGroup(AuthorizedActionTakers), + Unfreeze(AuthorizedActionTakers), + UnfreezeAdminGroup(AuthorizedActionTakers), + DestroyFrozenFunds(AuthorizedActionTakers), + DestroyFrozenFundsAdminGroup(AuthorizedActionTakers), + EmergencyAction(AuthorizedActionTakers), + EmergencyActionAdminGroup(AuthorizedActionTakers), + MainControlGroup(Option), +} + +impl TokenConfigurationChangeItem { + pub fn u8_item_index(&self) -> u8 { + match self { + TokenConfigurationChangeItem::TokenConfigurationNoChange => 0, + TokenConfigurationChangeItem::Conventions(_) => 1, + TokenConfigurationChangeItem::ConventionsControlGroup(_) => 2, + TokenConfigurationChangeItem::ConventionsAdminGroup(_) => 3, + TokenConfigurationChangeItem::MaxSupply(_) => 4, + TokenConfigurationChangeItem::MaxSupplyControlGroup(_) => 5, + TokenConfigurationChangeItem::MaxSupplyAdminGroup(_) => 6, + TokenConfigurationChangeItem::NewTokensDestinationIdentity(_) => 7, + TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup(_) => 8, + TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(_) => 9, + TokenConfigurationChangeItem::MintingAllowChoosingDestination(_) => 10, + TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup(_) => 11, + TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup(_) => 12, + TokenConfigurationChangeItem::ManualMinting(_) => 13, + TokenConfigurationChangeItem::ManualMintingAdminGroup(_) => 14, + TokenConfigurationChangeItem::ManualBurning(_) => 15, + TokenConfigurationChangeItem::ManualBurningAdminGroup(_) => 16, + TokenConfigurationChangeItem::Freeze(_) => 17, + TokenConfigurationChangeItem::FreezeAdminGroup(_) => 18, + TokenConfigurationChangeItem::Unfreeze(_) => 19, + TokenConfigurationChangeItem::UnfreezeAdminGroup(_) => 20, + TokenConfigurationChangeItem::DestroyFrozenFunds(_) => 21, + TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(_) => 22, + TokenConfigurationChangeItem::EmergencyAction(_) => 23, + TokenConfigurationChangeItem::EmergencyActionAdminGroup(_) => 24, + TokenConfigurationChangeItem::MainControlGroup(_) => 25, + } + } +} + +impl fmt::Display for TokenConfigurationChangeItem { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenConfigurationChangeItem::TokenConfigurationNoChange => { + write!(f, "No Change in Token Configuration") + } + TokenConfigurationChangeItem::Conventions(convention) => { + write!(f, "Conventions: {}", convention) + } + TokenConfigurationChangeItem::ConventionsControlGroup(control_group) => { + write!(f, "Conventions Control Group: {}", control_group) + } + TokenConfigurationChangeItem::ConventionsAdminGroup(admin_group) => { + write!(f, "Conventions Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::MaxSupply(max_supply) => match max_supply { + Some(amount) => write!(f, "Max Supply: {}", amount), + None => write!(f, "Max Supply: No Limit"), + }, + TokenConfigurationChangeItem::MaxSupplyControlGroup(control_group) => { + write!(f, "Max Supply Control Group: {}", control_group) + } + TokenConfigurationChangeItem::MaxSupplyAdminGroup(admin_group) => { + write!(f, "Max Supply Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::NewTokensDestinationIdentity(identity) => { + match identity { + Some(id) => write!(f, "New Tokens Destination Identity: {}", id), + None => write!(f, "New Tokens Destination Identity: None"), + } + } + TokenConfigurationChangeItem::NewTokensDestinationIdentityControlGroup( + control_group, + ) => { + write!( + f, + "New Tokens Destination Identity Control Group: {}", + control_group + ) + } + TokenConfigurationChangeItem::NewTokensDestinationIdentityAdminGroup(admin_group) => { + write!( + f, + "New Tokens Destination Identity Admin Group: {}", + admin_group + ) + } + TokenConfigurationChangeItem::MintingAllowChoosingDestination(allow) => { + write!(f, "Minting Allow Choosing Destination: {}", allow) + } + TokenConfigurationChangeItem::MintingAllowChoosingDestinationControlGroup( + control_group, + ) => { + write!( + f, + "Minting Allow Choosing Destination Control Group: {}", + control_group + ) + } + TokenConfigurationChangeItem::MintingAllowChoosingDestinationAdminGroup( + admin_group, + ) => { + write!( + f, + "Minting Allow Choosing Destination Admin Group: {}", + admin_group + ) + } + TokenConfigurationChangeItem::ManualMinting(control_group) => { + write!(f, "Manual Minting: {}", control_group) + } + TokenConfigurationChangeItem::ManualMintingAdminGroup(admin_group) => { + write!(f, "Manual Minting Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::ManualBurning(control_group) => { + write!(f, "Manual Burning: {}", control_group) + } + TokenConfigurationChangeItem::ManualBurningAdminGroup(admin_group) => { + write!(f, "Manual Burning Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::Freeze(control_group) => { + write!(f, "Freeze: {}", control_group) + } + TokenConfigurationChangeItem::FreezeAdminGroup(admin_group) => { + write!(f, "Freeze Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::Unfreeze(control_group) => { + write!(f, "Unfreeze: {}", control_group) + } + TokenConfigurationChangeItem::UnfreezeAdminGroup(admin_group) => { + write!(f, "Unfreeze Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::DestroyFrozenFunds(control_group) => { + write!(f, "Destroy Frozen Funds: {}", control_group) + } + TokenConfigurationChangeItem::DestroyFrozenFundsAdminGroup(admin_group) => { + write!(f, "Destroy Frozen Funds Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::EmergencyAction(control_group) => { + write!(f, "Emergency Action: {}", control_group) + } + TokenConfigurationChangeItem::EmergencyActionAdminGroup(admin_group) => { + write!(f, "Emergency Action Admin Group: {}", admin_group) + } + TokenConfigurationChangeItem::MainControlGroup(position) => match position { + Some(pos) => write!(f, "Main Control Group: {}", pos), + None => write!(f, "Main Control Group: None"), + }, + } + } +} 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 7a23c4259d..97e83ac6eb 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,13 +1,16 @@ use crate::data_contract::group::accessors::v0::GroupV0Getters; use crate::data_contract::group::{Group, GroupMemberPower}; use crate::data_contract::GroupContractPosition; -use crate::multi_identity_events::ActionTaker; +use crate::group::action_taker::{ActionGoal, ActionTaker}; use bincode::{Decode, Encode}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +use std::fmt; -#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, Default)] +#[derive( + Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, PartialOrd, Default, +)] pub enum AuthorizedActionTakers { #[default] NoOne, @@ -16,13 +19,25 @@ pub enum AuthorizedActionTakers { Group(GroupContractPosition), } +impl fmt::Display for AuthorizedActionTakers { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + AuthorizedActionTakers::NoOne => write!(f, "NoOne"), + AuthorizedActionTakers::ContractOwner => write!(f, "ContractOwner"), + AuthorizedActionTakers::MainGroup => write!(f, "MainGroup"), + AuthorizedActionTakers::Group(position) => write!(f, "Group(Position: {})", position), + } + } +} + impl AuthorizedActionTakers { pub fn allowed_for_action_taker( &self, contract_owner_id: &Identifier, - main_group: Option<&Group>, + main_group: Option, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, ) -> bool { match self { // No one is allowed @@ -38,8 +53,19 @@ impl AuthorizedActionTakers { // MainGroup allows multiparty actions with specific power requirements AuthorizedActionTakers::MainGroup => { - if let Some(main_group) = main_group { - Self::is_action_taker_authorized(main_group, action_taker) + if let Some(main_group_contract_position) = &main_group { + if let Some(group) = groups.get(main_group_contract_position) { + match goal { + ActionGoal::ActionCompletion => { + Self::is_action_taker_authorized(group, action_taker) + } + ActionGoal::ActionParticipation => { + Self::is_action_taker_participant(group, action_taker) + } + } + } else { + false + } } else { false } @@ -48,7 +74,14 @@ impl AuthorizedActionTakers { // Group-specific permissions with power aggregation logic AuthorizedActionTakers::Group(group_contract_position) => { if let Some(group) = groups.get(group_contract_position) { - Self::is_action_taker_authorized(group, action_taker) + match goal { + ActionGoal::ActionCompletion => { + Self::is_action_taker_authorized(group, action_taker) + } + ActionGoal::ActionParticipation => { + Self::is_action_taker_participant(group, action_taker) + } + } } else { false } @@ -77,4 +110,15 @@ impl AuthorizedActionTakers { } } } + + /// Helper method to check if action takers are participants. + fn is_action_taker_participant(group: &Group, action_taker: &ActionTaker) -> bool { + match action_taker { + ActionTaker::SingleIdentity(member_id) => group.members().get(member_id).is_some(), + ActionTaker::SpecifiedIdentities(_) => { + // this is made only for single identities + false + } + } + } } diff --git a/packages/rs-dpp/src/data_contract/change_control_rules/mod.rs b/packages/rs-dpp/src/data_contract/change_control_rules/mod.rs index 2385e11435..105580133b 100644 --- a/packages/rs-dpp/src/data_contract/change_control_rules/mod.rs +++ b/packages/rs-dpp/src/data_contract/change_control_rules/mod.rs @@ -5,7 +5,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::group::Group; use crate::data_contract::GroupContractPosition; -use crate::multi_identity_events::ActionTaker; +use crate::group::action_taker::{ActionGoal, ActionTaker}; use bincode::{Decode, Encode}; use derive_more::From; use platform_value::Identifier; @@ -18,31 +18,100 @@ pub enum ChangeControlRules { } impl ChangeControlRules { + pub fn admin_action_takers(&self) -> &AuthorizedActionTakers { + match self { + ChangeControlRules::V0(v0) => &v0.admin_action_takers, + } + } pub fn authorized_to_make_change_action_takers(&self) -> &AuthorizedActionTakers { match self { ChangeControlRules::V0(v0) => &v0.authorized_to_make_change, } } + + pub fn set_admin_action_takers(&mut self, admin_action_takers: AuthorizedActionTakers) { + match self { + ChangeControlRules::V0(v0) => { + v0.admin_action_takers = admin_action_takers; + } + } + } + + pub fn set_authorized_to_make_change_action_takers( + &mut self, + authorized_to_make_change: AuthorizedActionTakers, + ) { + match self { + ChangeControlRules::V0(v0) => { + v0.authorized_to_make_change = authorized_to_make_change; + } + } + } + pub fn can_make_change( &self, contract_owner_id: &Identifier, - main_group: Option<&Group>, + main_group: Option, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, ) -> bool { match self { ChangeControlRules::V0(v0) => { - v0.can_make_change(contract_owner_id, main_group, groups, action_taker) + v0.can_make_change(contract_owner_id, main_group, groups, action_taker, goal) } } } + + pub fn can_change_authorized_action_takers( + &self, + controlling_action_takers: &AuthorizedActionTakers, + contract_owner_id: &Identifier, + main_group: Option, + groups: &BTreeMap, + action_taker: &ActionTaker, + goal: ActionGoal, + ) -> bool { + match self { + ChangeControlRules::V0(v0) => v0.can_change_authorized_action_takers( + controlling_action_takers, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + } + } + + pub fn can_change_admin_action_takers( + &self, + admin_action_takers: &AuthorizedActionTakers, + contract_owner_id: &Identifier, + main_group: Option, + groups: &BTreeMap, + action_taker: &ActionTaker, + goal: ActionGoal, + ) -> bool { + match self { + ChangeControlRules::V0(v0) => v0.can_change_admin_action_takers( + admin_action_takers, + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ), + } + } pub fn can_change_to( &self, other: &ChangeControlRules, contract_owner_id: &Identifier, - main_group: Option<&Group>, + main_group: Option, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, ) -> bool { match (self, other) { (ChangeControlRules::V0(v0), ChangeControlRules::V0(v0_other)) => v0.can_change_to( @@ -51,6 +120,7 @@ impl ChangeControlRules { main_group, groups, action_taker, + goal, ), } } diff --git a/packages/rs-dpp/src/data_contract/change_control_rules/v0/mod.rs b/packages/rs-dpp/src/data_contract/change_control_rules/v0/mod.rs index 41261680ce..f5f4254a2a 100644 --- a/packages/rs-dpp/src/data_contract/change_control_rules/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/change_control_rules/v0/mod.rs @@ -1,7 +1,7 @@ use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; use crate::data_contract::group::Group; use crate::data_contract::GroupContractPosition; -use crate::multi_identity_events::ActionTaker; +use crate::group::action_taker::{ActionGoal, ActionTaker}; use bincode::{Decode, Encode}; use platform_value::Identifier; use serde::{Deserialize, Serialize}; @@ -12,35 +12,89 @@ pub struct ChangeControlRulesV0 { /// This is who is authorized to make such a change pub authorized_to_make_change: AuthorizedActionTakers, /// This is who is authorized to make such a change to the people authorized to make a change - pub authorized_to_change_authorized_action_takers: AuthorizedActionTakers, + pub admin_action_takers: AuthorizedActionTakers, /// Are we allowed to change to None in the future pub changing_authorized_action_takers_to_no_one_allowed: bool, - /// Are we allowed to change to None in the future - pub changing_authorized_action_takers_to_contract_owner_allowed: bool, + /// Are we allowed to change the admin action takers to no one in the future + pub changing_admin_action_takers_to_no_one_allowed: bool, + /// Can the admin action takers change themselves + pub self_changing_admin_action_takers_allowed: bool, } impl ChangeControlRulesV0 { pub fn can_make_change( &self, contract_owner_id: &Identifier, - main_group: Option<&Group>, + main_group: Option, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, ) -> bool { self.authorized_to_make_change.allowed_for_action_taker( contract_owner_id, main_group, groups, action_taker, + goal, + ) + } + pub fn can_change_authorized_action_takers( + &self, + controlling_action_takers: &AuthorizedActionTakers, + contract_owner_id: &Identifier, + main_group: Option, + groups: &BTreeMap, + action_taker: &ActionTaker, + goal: ActionGoal, + ) -> bool { + if !self.changing_authorized_action_takers_to_no_one_allowed + && controlling_action_takers == &AuthorizedActionTakers::NoOne + { + return false; + } + self.admin_action_takers.allowed_for_action_taker( + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) + } + + pub fn can_change_admin_action_takers( + &self, + admin_action_takers: &AuthorizedActionTakers, + contract_owner_id: &Identifier, + main_group: Option, + groups: &BTreeMap, + action_taker: &ActionTaker, + goal: ActionGoal, + ) -> bool { + if !self.self_changing_admin_action_takers_allowed { + return false; + } + if !self.changing_admin_action_takers_to_no_one_allowed + && admin_action_takers == &AuthorizedActionTakers::NoOne + { + return false; + } + self.admin_action_takers.allowed_for_action_taker( + contract_owner_id, + main_group, + groups, + action_taker, + goal, ) } + pub fn can_change_to( &self, other: &ChangeControlRulesV0, contract_owner_id: &Identifier, - main_group: Option<&Group>, + main_group: Option, groups: &BTreeMap, action_taker: &ActionTaker, + goal: ActionGoal, ) -> bool { // First, check if the action taker is allowed to make any changes at all if !self.authorized_to_make_change.allowed_for_action_taker( @@ -48,6 +102,7 @@ impl ChangeControlRulesV0 { main_group, groups, action_taker, + goal, ) { return false; } @@ -56,10 +111,13 @@ impl ChangeControlRulesV0 { if self.authorized_to_make_change != other.authorized_to_make_change { // Changing the authorized action takers requires the action_taker to be allowed by // authorized_to_change_authorized_action_takers in the current rules - if !self - .authorized_to_change_authorized_action_takers - .allowed_for_action_taker(contract_owner_id, main_group, groups, action_taker) - { + if !self.admin_action_takers.allowed_for_action_taker( + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) { return false; } @@ -69,41 +127,28 @@ impl ChangeControlRulesV0 { return false; } } - - // If we are changing to ContractOwner, ensure it's allowed - if let AuthorizedActionTakers::ContractOwner = other.authorized_to_make_change { - if !self.changing_authorized_action_takers_to_contract_owner_allowed { - return false; - } - } } // Check if authorized_to_change_authorized_action_takers is being modified - if self.authorized_to_change_authorized_action_takers - != other.authorized_to_change_authorized_action_takers - { - // Must be allowed by the current authorized_to_change_authorized_action_takers - if !self - .authorized_to_change_authorized_action_takers - .allowed_for_action_taker(contract_owner_id, main_group, groups, action_taker) - { + if self.admin_action_takers != other.admin_action_takers { + if !self.self_changing_admin_action_takers_allowed { return false; } - // If we are changing to NoOne, ensure it's allowed - if let AuthorizedActionTakers::NoOne = - other.authorized_to_change_authorized_action_takers - { - if !self.changing_authorized_action_takers_to_no_one_allowed { - return false; - } + // Must be allowed by the current authorized_to_change_authorized_action_takers + if !self.admin_action_takers.allowed_for_action_taker( + contract_owner_id, + main_group, + groups, + action_taker, + goal, + ) { + return false; } - // If we are changing to ContractOwner, ensure it's allowed - if let AuthorizedActionTakers::ContractOwner = - other.authorized_to_change_authorized_action_takers - { - if !self.changing_authorized_action_takers_to_contract_owner_allowed { + // If we are changing to NoOne, ensure it's allowed + if let AuthorizedActionTakers::NoOne = other.admin_action_takers { + if !self.changing_admin_action_takers_to_no_one_allowed { return false; } } diff --git a/packages/rs-dpp/src/data_contract/group/methods/mod.rs b/packages/rs-dpp/src/data_contract/group/methods/mod.rs new file mode 100644 index 0000000000..2d24cd45f5 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/group/methods/mod.rs @@ -0,0 +1 @@ +pub mod v0; diff --git a/packages/rs-dpp/src/data_contract/group/methods/v0/mod.rs b/packages/rs-dpp/src/data_contract/group/methods/v0/mod.rs new file mode 100644 index 0000000000..c57a7ad227 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/group/methods/v0/mod.rs @@ -0,0 +1,10 @@ +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +pub trait GroupMethodsV0 { + fn validate( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} diff --git a/packages/rs-dpp/src/data_contract/group/mod.rs b/packages/rs-dpp/src/data_contract/group/mod.rs index 26e3c03629..9f8f4cc97b 100644 --- a/packages/rs-dpp/src/data_contract/group/mod.rs +++ b/packages/rs-dpp/src/data_contract/group/mod.rs @@ -1,14 +1,19 @@ use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; +use crate::data_contract::group::methods::v0::GroupMethodsV0; use crate::data_contract::group::v0::GroupV0; use crate::errors::ProtocolError; +use crate::validation::SimpleConsensusValidationResult; use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; +use platform_version::version::PlatformVersion; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; pub mod accessors; +pub(crate) mod methods; pub mod v0; + pub type RequiredSigners = u8; pub type GroupMemberPower = u32; @@ -81,3 +86,14 @@ impl GroupV0Setters for Group { } } } + +impl GroupMethodsV0 for Group { + fn validate( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match self { + Group::V0(group_v0) => group_v0.validate(platform_version), + } + } +} 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 c53696e9b2..c4b04befcc 100644 --- a/packages/rs-dpp/src/data_contract/group/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/group/v0/mod.rs @@ -1,9 +1,17 @@ +use crate::consensus::basic::data_contract::{ + GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, + GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, + GroupTotalPowerLessThanRequiredError, +}; use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; +use crate::data_contract::group::methods::v0::GroupMethodsV0; use crate::data_contract::group::{GroupMemberPower, GroupRequiredPower}; +use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; +use platform_version::version::PlatformVersion; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -66,3 +74,82 @@ impl GroupV0Setters for GroupV0 { self.required_power = required_power; } } + +impl GroupMethodsV0 for GroupV0 { + /// Validates the group to ensure: + /// - The sum of all group member powers is equal to or greater than the required power. + /// - No group member has a power of 0. + /// - The group does not exceed the maximum allowed members (256). + /// + /// # Returns + /// - `Ok(SimpleConsensusValidationResult)` if the group is valid. + /// - `Err(ProtocolError)` if validation fails due to an invalid group configuration. + fn validate( + &self, + platform_version: &PlatformVersion, + ) -> Result { + let max_group_members = platform_version.system_limits.max_contract_group_size; + const GROUP_POWER_LIMIT: GroupMemberPower = u16::MAX as GroupMemberPower; + + // Check the number of members does not exceed the maximum allowed + if self.members.len() as u32 > max_group_members { + return Ok(SimpleConsensusValidationResult::new_with_error( + GroupExceedsMaxMembersError::new(max_group_members).into(), + )); + } + + let mut total_power: GroupMemberPower = 0; + + let mut total_power_without_unilateral_members: GroupMemberPower = 0; + + // Iterate over members to validate their power and calculate the total power + for (&member, &power) in &self.members { + if power == 0 { + return Ok(SimpleConsensusValidationResult::new_with_error( + GroupMemberHasPowerOfZeroError::new(member).into(), + )); + } + if power > GROUP_POWER_LIMIT { + return Ok(SimpleConsensusValidationResult::new_with_error( + GroupMemberHasPowerOverLimitError::new(member, power, GROUP_POWER_LIMIT).into(), + )); + } + if power > self.required_power { + return Ok(SimpleConsensusValidationResult::new_with_error( + GroupMemberHasPowerOverLimitError::new(member, power, self.required_power) + .into(), + )); + } + total_power = total_power + .checked_add(power) + .ok_or_else(|| ProtocolError::Overflow("Total power overflowed"))?; + + if power < self.required_power { + total_power_without_unilateral_members = total_power_without_unilateral_members + .checked_add(power) + .ok_or_else(|| ProtocolError::Overflow("Total power overflowed"))?; + } + } + + // Check if the total power meets the required power + if total_power < self.required_power { + return Ok(SimpleConsensusValidationResult::new_with_error( + GroupTotalPowerLessThanRequiredError::new(total_power, self.required_power).into(), + )); + } + + // Check if the total power without unilateral members meets the required power + if total_power_without_unilateral_members < self.required_power { + return Ok(SimpleConsensusValidationResult::new_with_error( + GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError::new( + total_power_without_unilateral_members, + self.required_power, + ) + .into(), + )); + } + + // If all validations pass, return an empty validation result + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-dpp/src/data_contract/methods/mod.rs b/packages/rs-dpp/src/data_contract/methods/mod.rs index d9bde273a7..20b64863c0 100644 --- a/packages/rs-dpp/src/data_contract/methods/mod.rs +++ b/packages/rs-dpp/src/data_contract/methods/mod.rs @@ -2,4 +2,6 @@ pub mod schema; #[cfg(feature = "validation")] pub mod validate_document; #[cfg(feature = "validation")] +pub mod validate_groups; +#[cfg(feature = "validation")] pub mod validate_update; diff --git a/packages/rs-dpp/src/data_contract/methods/validate_groups/mod.rs b/packages/rs-dpp/src/data_contract/methods/validate_groups/mod.rs new file mode 100644 index 0000000000..d6a6bef8a8 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/methods/validate_groups/mod.rs @@ -0,0 +1,58 @@ +use crate::data_contract::group::Group; +use crate::data_contract::GroupContractPosition; +use crate::prelude::DataContract; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +mod v0; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; + +impl DataContract { + /// Validates the provided groups to ensure they meet the requirements for data contracts. + /// + /// # Parameters + /// - `groups`: A reference to a `BTreeMap` of group contract positions (`GroupContractPosition`) + /// mapped to their corresponding `Group` objects. These represent the groups associated with + /// the data contract. + /// - `platform_version`: A reference to the [`PlatformVersion`](crate::version::PlatformVersion) + /// object specifying the version of the platform and determining which validation method to use. + /// + /// # Returns + /// - `Ok(SimpleConsensusValidationResult)` if all the groups pass validation: + /// - Group contract positions must be contiguous, i.e., no gaps between positions. + /// - Each group must meet its individual validation criteria. + /// - `Err(ProtocolError)` if: + /// - An unknown or unsupported platform version is provided. + /// - Validation of any group fails. + /// + /// # Behavior + /// - Delegates the actual validation logic to the appropriate versioned implementation + /// (`validate_groups_v0`) based on the provided platform version. + /// - If an unknown platform version is encountered, a `ProtocolError::UnknownVersionMismatch` + /// is returned. + /// + /// # Errors + /// - Returns a `ProtocolError::UnknownVersionMismatch` if the platform version is not recognized. + /// - Returns validation errors for: + /// - Non-contiguous group contract positions (`NonContiguousContractGroupPositionsError`). + /// - Invalid individual group configurations (e.g., power-related errors or exceeding member limits). + pub fn validate_groups( + groups: &BTreeMap, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .contract_versions + .methods + .validate_groups + { + 0 => Self::validate_groups_v0(groups, platform_version), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DataContract::validate_groups".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/data_contract/methods/validate_groups/v0/mod.rs b/packages/rs-dpp/src/data_contract/methods/validate_groups/v0/mod.rs new file mode 100644 index 0000000000..b6f4fc2753 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/methods/validate_groups/v0/mod.rs @@ -0,0 +1,39 @@ +use crate::consensus::basic::data_contract::NonContiguousContractGroupPositionsError; +use crate::data_contract::group::methods::v0::GroupMethodsV0; +use crate::data_contract::group::Group; +use crate::data_contract::{DataContract, GroupContractPosition}; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +impl DataContract { + #[inline(always)] + pub(super) fn validate_groups_v0( + groups: &BTreeMap, + platform_version: &PlatformVersion, + ) -> Result { + // Check for gaps in the group contract positions + let mut expected_position = 0; + for &position in groups.keys() { + if position != expected_position { + return Ok(SimpleConsensusValidationResult::new_with_error( + NonContiguousContractGroupPositionsError::new(expected_position, position) + .into(), + )); + } + expected_position += 1; + } + + // Validate each group individually + for group in groups.values() { + let validation_result = group.validate(platform_version)?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + } + + // If we reach here, everything is valid + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs b/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs index fed077b712..21b9fc6183 100644 --- a/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/methods/validate_update/v0/mod.rs @@ -3,8 +3,10 @@ use crate::data_contract::accessors::v0::DataContractV0Getters; use crate::consensus::basic::data_contract::{ IncompatibleDataContractSchemaError, InvalidDataContractVersionError, }; +use crate::consensus::state::data_contract::data_contract_update_action_not_allowed_error::DataContractUpdateActionNotAllowedError; use crate::consensus::state::data_contract::data_contract_update_permission_error::DataContractUpdatePermissionError; use crate::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; +use crate::data_contract::accessors::v1::DataContractV1Getters; use crate::data_contract::document_type::schema::validate_schema_compatibility; use crate::data_contract::schema::DataContractSchemaMethodsV0; use crate::data_contract::DataContract; @@ -164,6 +166,86 @@ impl DataContract { return Ok(SimpleConsensusValidationResult::new_with_errors(errors)); } } + + if self.groups() != new_data_contract.groups() { + // No groups can have been removed + for old_group_position in self.groups().keys() { + if !new_data_contract.groups().contains_key(old_group_position) { + return Ok(SimpleConsensusValidationResult::new_with_error( + DataContractUpdateActionNotAllowedError::new( + self.id(), + "remove group".to_string(), + ) + .into(), + )); + } + } + + // Ensure no group has been changed + for (old_group_position, old_group) in self.groups() { + if let Some(new_group) = new_data_contract.groups().get(old_group_position) { + if old_group != new_group { + return Ok(SimpleConsensusValidationResult::new_with_error( + DataContractUpdateActionNotAllowedError::new( + self.id(), + format!( + "change group at position {} is not allowed", + old_group_position + ), + ) + .into(), + )); + } + } + } + + let valid = + DataContract::validate_groups(new_data_contract.groups(), platform_version)?; + if !valid.is_valid() { + return Ok(valid); + } + } + + if self.tokens() != new_data_contract.tokens() { + for (token_position, old_token_config) in self.tokens() { + // Check if a token has been removed + if !new_data_contract.tokens().contains_key(token_position) { + return Ok(SimpleConsensusValidationResult::new_with_error( + DataContractUpdateActionNotAllowedError::new( + self.id(), + format!("remove token at position {}", token_position), + ) + .into(), + )); + } + + // Check if a token configuration has been changed + if let Some(new_token_config) = new_data_contract.tokens().get(token_position) { + if old_token_config != new_token_config { + return Ok(SimpleConsensusValidationResult::new_with_error( + DataContractUpdateActionNotAllowedError::new( + self.id(), + format!("update token at position {}", token_position), + ) + .into(), + )); + } + } + } + + // Check if a token has been added + for token_position in new_data_contract.tokens().keys() { + if !self.tokens().contains_key(token_position) { + return Ok(SimpleConsensusValidationResult::new_with_error( + DataContractUpdateActionNotAllowedError::new( + self.id(), + format!("add token at position {}", token_position), + ) + .into(), + )); + } + } + } } Ok(SimpleConsensusValidationResult::new()) diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index e99398b757..e89758dde7 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -11,9 +11,11 @@ use crate::consensus::basic::data_contract::{ DataContractHaveNewUniqueIndexError, DataContractImmutablePropertiesUpdateError, DataContractInvalidIndexDefinitionUpdateError, DataContractTokenConfigurationUpdateError, DataContractUniqueIndicesChangedError, DuplicateIndexError, DuplicateIndexNameError, - IncompatibleDataContractSchemaError, IncompatibleDocumentTypeSchemaError, - IncompatibleRe2PatternError, InvalidCompoundIndexError, InvalidDataContractIdError, - InvalidDataContractVersionError, InvalidDocumentTypeNameError, + GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, + GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, + GroupTotalPowerLessThanRequiredError, IncompatibleDataContractSchemaError, + IncompatibleDocumentTypeSchemaError, IncompatibleRe2PatternError, InvalidCompoundIndexError, + InvalidDataContractIdError, InvalidDataContractVersionError, InvalidDocumentTypeNameError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidIndexPropertyTypeError, InvalidIndexedPropertyConstraintError, InvalidTokenBaseSupplyError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, @@ -439,6 +441,9 @@ pub enum BasicError { #[error(transparent)] InvalidGroupPositionError(InvalidGroupPositionError), + #[error(transparent)] + GroupPositionDoesNotExistError(GroupPositionDoesNotExistError), + #[error(transparent)] InvalidActionIdError(InvalidActionIdError), @@ -450,6 +455,23 @@ pub enum BasicError { #[error(transparent)] GroupActionNotAllowedOnTransitionError(GroupActionNotAllowedOnTransitionError), + + #[error(transparent)] + GroupExceedsMaxMembersError(GroupExceedsMaxMembersError), + + #[error(transparent)] + GroupMemberHasPowerOfZeroError(GroupMemberHasPowerOfZeroError), + + #[error(transparent)] + GroupMemberHasPowerOverLimitError(GroupMemberHasPowerOverLimitError), + + #[error(transparent)] + GroupTotalPowerLessThanRequiredError(GroupTotalPowerLessThanRequiredError), + + #[error(transparent)] + GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError( + GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, + ), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_exceeds_max_members_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_exceeds_max_members_error.rs new file mode 100644 index 0000000000..adc124655a --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_exceeds_max_members_error.rs @@ -0,0 +1,31 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Group exceeds the maximum allowed number of members: {max_members}")] +#[platform_serialize(unversioned)] +pub struct GroupExceedsMaxMembersError { + max_members: u32, +} + +impl GroupExceedsMaxMembersError { + pub fn new(max_members: u32) -> Self { + Self { max_members } + } + + pub fn max_members(&self) -> u32 { + self.max_members + } +} + +impl From for ConsensusError { + fn from(err: GroupExceedsMaxMembersError) -> Self { + Self::BasicError(BasicError::GroupExceedsMaxMembersError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_member_has_power_of_zero_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_member_has_power_of_zero_error.rs new file mode 100644 index 0000000000..4d3b9c37d8 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_member_has_power_of_zero_error.rs @@ -0,0 +1,32 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use crate::identifier::Identifier; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Member {member_id} has a power of 0, which is not allowed")] +#[platform_serialize(unversioned)] +pub struct GroupMemberHasPowerOfZeroError { + member_id: Identifier, +} + +impl GroupMemberHasPowerOfZeroError { + pub fn new(member_id: Identifier) -> Self { + Self { member_id } + } + + pub fn member_id(&self) -> Identifier { + self.member_id + } +} + +impl From for ConsensusError { + fn from(err: GroupMemberHasPowerOfZeroError) -> Self { + Self::BasicError(BasicError::GroupMemberHasPowerOfZeroError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_member_has_power_over_limit_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_member_has_power_over_limit_error.rs new file mode 100644 index 0000000000..40bbd70a60 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_member_has_power_over_limit_error.rs @@ -0,0 +1,57 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::group::GroupMemberPower; +use crate::errors::ProtocolError; +use crate::identifier::Identifier; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Member {member_id} has a power of {power}, which exceeds the allowed limit of {max_power}" +)] +#[platform_serialize(unversioned)] +pub struct GroupMemberHasPowerOverLimitError { + member_id: Identifier, + power: GroupMemberPower, + max_power: GroupMemberPower, +} + +impl GroupMemberHasPowerOverLimitError { + /// Creates a new `GroupMemberHasPowerOverLimitError`. + pub fn new( + member_id: Identifier, + power: GroupMemberPower, + max_power: GroupMemberPower, + ) -> Self { + Self { + member_id, + power, + max_power, + } + } + + /// Returns the identifier of the member. + pub fn member_id(&self) -> Identifier { + self.member_id + } + + /// Returns the power of the member. + pub fn power(&self) -> GroupMemberPower { + self.power + } + + /// Returns the maximum allowed power. + pub fn max_power(&self) -> GroupMemberPower { + self.max_power + } +} + +impl From for ConsensusError { + fn from(err: GroupMemberHasPowerOverLimitError) -> Self { + Self::BasicError(BasicError::GroupMemberHasPowerOverLimitError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_non_unilateral_member_power_has_less_than_required_power_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_non_unilateral_member_power_has_less_than_required_power_error.rs new file mode 100644 index 0000000000..7d8632fc53 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_non_unilateral_member_power_has_less_than_required_power_error.rs @@ -0,0 +1,49 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::group::GroupMemberPower; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("The collective power of non-unilateral members {total_power} is less than the required power {required_power}")] +#[platform_serialize(unversioned)] +pub struct GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError { + total_power: GroupMemberPower, + required_power: GroupMemberPower, +} + +impl GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError { + /// Creates a new `GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError`. + /// + /// # Parameters + /// - `total_power`: The total power of non-unilateral members. + /// - `required_power`: The required power to meet the threshold. + pub fn new(total_power: GroupMemberPower, required_power: GroupMemberPower) -> Self { + Self { + total_power, + required_power, + } + } + + /// Returns the total power of non-unilateral members. + pub fn total_power(&self) -> GroupMemberPower { + self.total_power + } + + /// Returns the required power to meet the threshold. + pub fn required_power(&self) -> GroupMemberPower { + self.required_power + } +} + +impl From for ConsensusError { + fn from(err: GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError) -> Self { + Self::BasicError( + BasicError::GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError(err), + ) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_position_does_not_exist_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_position_does_not_exist_error.rs new file mode 100644 index 0000000000..7f52548936 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_position_does_not_exist_error.rs @@ -0,0 +1,46 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::GroupContractPosition; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +/// Error raised when a group position does not exist in the data contract. +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Group position {} does not exist", missing_group_position)] +#[platform_serialize(unversioned)] +pub struct GroupPositionDoesNotExistError { + missing_group_position: GroupContractPosition, +} + +impl GroupPositionDoesNotExistError { + /// Creates a new instance of `GroupPositionDoesNotExistError`. + /// + /// # Parameters + /// - `missing_group_position`: The group position that does not exist. + /// + /// # Returns + /// A new `GroupPositionDoesNotExistError` instance. + pub fn new(missing_group_position: GroupContractPosition) -> Self { + Self { + missing_group_position, + } + } + + /// Gets the missing group position that caused this error. + /// + /// # Returns + /// The missing group position. + pub fn missing_group_position(&self) -> GroupContractPosition { + self.missing_group_position + } +} + +impl From for ConsensusError { + fn from(err: GroupPositionDoesNotExistError) -> Self { + Self::BasicError(BasicError::GroupPositionDoesNotExistError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_total_power_has_less_than_required_power_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_total_power_has_less_than_required_power_error.rs new file mode 100644 index 0000000000..6559f20e5c --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/group_total_power_has_less_than_required_power_error.rs @@ -0,0 +1,40 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::group::GroupMemberPower; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Group total power {total_power} is less than the required power {required_power}")] +#[platform_serialize(unversioned)] +pub struct GroupTotalPowerLessThanRequiredError { + total_power: GroupMemberPower, + required_power: GroupMemberPower, +} + +impl GroupTotalPowerLessThanRequiredError { + pub fn new(total_power: GroupMemberPower, required_power: GroupMemberPower) -> Self { + Self { + total_power, + required_power, + } + } + + pub fn total_power(&self) -> GroupMemberPower { + self.total_power + } + + pub fn required_power(&self) -> GroupMemberPower { + self.required_power + } +} + +impl From for ConsensusError { + fn from(err: GroupTotalPowerLessThanRequiredError) -> Self { + Self::BasicError(BasicError::GroupTotalPowerLessThanRequiredError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs index 2fc29ce57f..529edda651 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs @@ -9,6 +9,12 @@ mod data_contract_unique_indices_changed_error; mod document_types_are_missing_error; mod duplicate_index_error; mod duplicate_index_name_error; +mod group_exceeds_max_members_error; +mod group_member_has_power_of_zero_error; +mod group_member_has_power_over_limit_error; +mod group_non_unilateral_member_power_has_less_than_required_power_error; +mod group_position_does_not_exist_error; +mod group_total_power_has_less_than_required_power_error; mod incompatible_data_contract_schema_error; mod incompatible_document_type_schema_error; mod incompatible_re2_pattern_error; @@ -58,6 +64,12 @@ pub use unique_indices_limit_reached_error::*; pub use contested_unique_index_on_mutable_document_type_error::*; pub use contested_unique_index_with_unique_index_error::*; +pub use group_exceeds_max_members_error::*; +pub use group_member_has_power_of_zero_error::*; +pub use group_member_has_power_over_limit_error::*; +pub use group_non_unilateral_member_power_has_less_than_required_power_error::*; +pub use group_position_does_not_exist_error::*; +pub use group_total_power_has_less_than_required_power_error::*; pub use incompatible_document_type_schema_error::*; pub use invalid_document_type_name_error::*; pub use invalid_token_base_supply_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 56f38cfaa2..00ee6d4da5 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -103,6 +103,16 @@ impl ErrorWithCode for BasicError { Self::NonContiguousContractGroupPositionsError(_) => 10252, Self::NonContiguousContractTokenPositionsError(_) => 10253, + // Group Errors: 10350-10399 + Self::InvalidGroupPositionError(_) => 10350, + Self::GroupPositionDoesNotExistError(_) => 10351, + Self::GroupActionNotAllowedOnTransitionError(_) => 10352, + Self::GroupTotalPowerLessThanRequiredError(_) => 10353, + Self::GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError(_) => 10354, + Self::GroupExceedsMaxMembersError(_) => 10355, + Self::GroupMemberHasPowerOfZeroError(_) => 10356, + Self::GroupMemberHasPowerOverLimitError(_) => 10357, + // Document Errors: 10400-10449 Self::DataContractNotPresentError { .. } => 10400, Self::DuplicateDocumentTransitionsWithIdsError { .. } => 10401, @@ -127,12 +137,11 @@ impl ErrorWithCode for BasicError { // Token Errors: 10450-10499 Self::InvalidTokenIdError(_) => 10450, Self::InvalidTokenPositionError(_) => 10451, - Self::InvalidGroupPositionError(_) => 10452, - Self::InvalidActionIdError(_) => 10453, - Self::ContractHasNoTokensError(_) => 10454, - Self::DestinationIdentityForTokenMintingNotSetError(_) => 10455, - Self::ChoosingTokenMintRecipientNotAllowedError(_) => 10456, - Self::TokenTransferToOurselfError(_) => 10457, + Self::InvalidActionIdError(_) => 10452, + Self::ContractHasNoTokensError(_) => 10453, + Self::DestinationIdentityForTokenMintingNotSetError(_) => 10454, + Self::ChoosingTokenMintRecipientNotAllowedError(_) => 10455, + Self::TokenTransferToOurselfError(_) => 10456, // Identity Errors: 10500-10599 Self::DuplicatedIdentityPublicKeyBasicError(_) => 10500, @@ -176,7 +185,6 @@ impl ErrorWithCode for BasicError { // General Errors 10700-10799 Self::OverflowError(_) => 10700, - Self::GroupActionNotAllowedOnTransitionError(_) => 10701, } } } @@ -215,6 +223,8 @@ impl ErrorWithCode for StateError { Self::DataContractAlreadyPresentError { .. } => 40000, Self::DataContractIsReadonlyError { .. } => 40001, Self::DataContractConfigUpdateError { .. } => 40002, + Self::DataContractUpdatePermissionError(_) => 40003, + Self::DataContractUpdateActionNotAllowedError(_) => 40004, // Document Errors: 40100-40149 Self::DocumentAlreadyPresentError { .. } => 40100, @@ -253,7 +263,6 @@ impl ErrorWithCode for StateError { Self::IdentityInsufficientBalanceError(_) => 40210, Self::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError(_) => 40211, Self::DocumentTypeUpdateError(_) => 40212, - Self::DataContractUpdatePermissionError(_) => 40213, Self::MissingTransferKeyError(_) => 40214, Self::NoTransferKeyForCoreWithdrawalAvailableError(_) => 40215, Self::RecipientIdentityDoesNotExistError(_) => 40216, diff --git a/packages/rs-dpp/src/errors/consensus/state/data_contract/data_contract_update_action_not_allowed_error.rs b/packages/rs-dpp/src/errors/consensus/state/data_contract/data_contract_update_action_not_allowed_error.rs new file mode 100644 index 0000000000..0064bc5923 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/data_contract/data_contract_update_action_not_allowed_error.rs @@ -0,0 +1,45 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Action '{action}' is not allowed on Data Contract {data_contract_id}")] +#[platform_serialize(unversioned)] +pub struct DataContractUpdateActionNotAllowedError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + data_contract_id: Identifier, + action: String, +} + +impl DataContractUpdateActionNotAllowedError { + pub fn new(data_contract_id: Identifier, action: impl Into) -> Self { + Self { + data_contract_id, + action: action.into(), + } + } + + pub fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + pub fn action(&self) -> &str { + &self.action + } +} + +impl From for ConsensusError { + fn from(err: DataContractUpdateActionNotAllowedError) -> Self { + Self::StateError(StateError::DataContractUpdateActionNotAllowedError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/data_contract/mod.rs b/packages/rs-dpp/src/errors/consensus/state/data_contract/mod.rs index 563596603d..c06986bb44 100644 --- a/packages/rs-dpp/src/errors/consensus/state/data_contract/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/data_contract/mod.rs @@ -1,5 +1,6 @@ pub mod data_contract_already_present_error; pub mod data_contract_config_update_error; pub mod data_contract_is_readonly_error; +pub mod data_contract_update_action_not_allowed_error; pub mod data_contract_update_permission_error; pub mod document_type_update_error; diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index 9dc0a2938b..91eaf396cc 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -25,6 +25,7 @@ use crate::consensus::state::identity::max_identity_public_key_limit_reached_err use crate::consensus::state::identity::missing_identity_public_key_ids_error::MissingIdentityPublicKeyIdsError; use crate::consensus::state::identity::{IdentityAlreadyExistsError, IdentityInsufficientBalanceError, RecipientIdentityDoesNotExistError}; use crate::consensus::ConsensusError; +use crate::consensus::state::data_contract::data_contract_update_action_not_allowed_error::DataContractUpdateActionNotAllowedError; use crate::consensus::state::data_contract::data_contract_update_permission_error::DataContractUpdatePermissionError; use crate::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; use crate::consensus::state::document::document_contest_currently_locked_error::DocumentContestCurrentlyLockedError; @@ -226,6 +227,9 @@ pub enum StateError { #[error(transparent)] GroupActionAlreadySignedByIdentityError(GroupActionAlreadySignedByIdentityError), + + #[error(transparent)] + DataContractUpdateActionNotAllowedError(DataContractUpdateActionNotAllowedError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/group/action_taker.rs b/packages/rs-dpp/src/group/action_taker.rs new file mode 100644 index 0000000000..61e5d10c1b --- /dev/null +++ b/packages/rs-dpp/src/group/action_taker.rs @@ -0,0 +1,13 @@ +use platform_value::Identifier; +use std::collections::BTreeSet; +#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Eq)] +pub enum ActionGoal { + ActionCompletion, + ActionParticipation, +} + +#[derive(Debug, PartialEq, PartialOrd, Clone, Eq)] +pub enum ActionTaker { + SingleIdentity(Identifier), + SpecifiedIdentities(BTreeSet), +} diff --git a/packages/rs-dpp/src/group/mod.rs b/packages/rs-dpp/src/group/mod.rs index aba7606668..427b62c775 100644 --- a/packages/rs-dpp/src/group/mod.rs +++ b/packages/rs-dpp/src/group/mod.rs @@ -7,6 +7,7 @@ use platform_value::Identifier; use serde::{Deserialize, Serialize}; pub mod action_event; +pub mod action_taker; pub mod group_action; pub mod group_action_status; diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index af7195d65c..4225704da9 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -41,7 +41,6 @@ pub mod block; /// Core subsidy pub mod core_subsidy; pub mod fee; -pub mod multi_identity_events; pub mod nft; pub mod prefunded_specialized_balance; pub mod serialization; diff --git a/packages/rs-dpp/src/multi_identity_events/mod.rs b/packages/rs-dpp/src/multi_identity_events/mod.rs deleted file mode 100644 index 6c6558cf9f..0000000000 --- a/packages/rs-dpp/src/multi_identity_events/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -use platform_value::Identifier; -use std::collections::BTreeSet; - -pub enum ActionTaker { - SingleIdentity(Identifier), - SpecifiedIdentities(BTreeSet), -} diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index da4c004287..88a3eddcfe 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -241,27 +241,6 @@ macro_rules! call_errorable_method_identity_signed { }; } -// TODO unused macros below -// macro_rules! call_static_method { -// ($state_transition:expr, $method:ident ) => { -// match $state_transition { -// StateTransition::DataContractCreate(_) => DataContractCreateTransition::$method(), -// StateTransition::DataContractUpdate(_) => DataContractUpdateTransition::$method(), -// StateTransition::DocumentsBatch(_) => DocumentsBatchTransition::$method(), -// StateTransition::IdentityCreate(_) => IdentityCreateTransition::$method(), -// StateTransition::IdentityTopUp(_) => IdentityTopUpTransition::$method(), -// StateTransition::IdentityCreditWithdrawal(_) => { -// IdentityCreditWithdrawalTransition::$method() -// } -// StateTransition::IdentityUpdate(_) => IdentityUpdateTransition::$method(), -// StateTransition::IdentityCreditTransfer(_) => { -// IdentityCreditTransferTransition::$method() -// } -// StateTransition::MasternodeVote(_) => MasternodeVote::$method(), -// } -// }; -// } - #[derive( Debug, Clone, @@ -379,6 +358,9 @@ impl StateTransition { BatchedTransitionRef::Token(TokenTransition::EmergencyAction(_)) => { "TokenEmergencyAction" } + BatchedTransitionRef::Token(TokenTransition::ConfigUpdate(_)) => { + "TokenConfigUpdate" + } }; document_transition_types.push(document_transition_name); } @@ -761,93 +743,3 @@ impl StateTransition { }) } } -// -// impl StateTransition { -// fn signature_property_paths(&self) -> Vec<&'static str> { -// call_static_method!(self, signature_property_paths) -// } -// -// fn identifiers_property_paths(&self) -> Vec<&'static str> { -// call_static_method!(self, identifiers_property_paths) -// } -// -// fn binary_property_paths(&self) -> Vec<&'static str> { -// call_static_method!(self, binary_property_paths) -// } -// -// pub fn get_owner_id(&self) -> &Identifier { -// call_method!(self, get_owner_id) -// } -// } -// -// impl StateTransitionFieldTypes for StateTransition { -// fn hash(&self, skip_signature: bool) -> Result, ProtocolError> { -// if skip_signature { -// Ok(hash::hash_to_vec(self.signable_bytes()?)) -// } else { -// Ok(hash::hash_to_vec(PlatformSerializable::serialize_to_bytes(self)?)) -// } -// } -// -// #[cfg(feature = "state-transition-cbor-conversion")] -// fn to_cbor_buffer(&self, _skip_signature: bool) -> Result, crate::ProtocolError> { -// call_method!(self, to_cbor_buffer, true) -// } -// -// #[cfg(feature = "state-transition-json-conversion")] -// fn to_json(&self, skip_signature: bool) -> Result { -// call_method!(self, to_json, skip_signature) -// } -// -// #[cfg(feature = "state-transition-value-conversion")] -// fn to_object( -// &self, -// skip_signature: bool, -// ) -> Result { -// call_method!(self, to_object, skip_signature) -// } -// -// fn signature_property_paths() -> Vec<&'static str> { -// panic!("Static call is not supported") -// } -// -// fn identifiers_property_paths() -> Vec<&'static str> { -// panic!("Static call is not supported") -// } -// -// fn binary_property_paths() -> Vec<&'static str> { -// panic!("Static call is not supported") -// } -// -// #[cfg(feature = "state-transition-value-conversion")] -// fn to_cleaned_object(&self, skip_signature: bool) -> Result { -// call_method!(self, to_cleaned_object, skip_signature) -// } -// } -// -// impl StateTransitionLike for StateTransition { -// fn state_transition_protocol_version(&self) -> FeatureVersion { -// call_method!(self, state_transition_protocol_version) -// } -// /// returns the type of State Transition -// fn state_transition_type(&self) -> StateTransitionType { -// call_method!(self, state_transition_type) -// } -// /// returns the signature as a byte-array -// fn signature(&self) -> &BinaryData { -// call_method!(self, signature) -// } -// -// /// set a new signature -// fn set_signature(&mut self, signature: BinaryData) { -// call_method!(self, set_signature, signature) -// } -// -// fn set_signature_bytes(&mut self, signature: Vec) { -// call_method!(self, set_signature_bytes, signature) -// } -// -// fn modified_data_ids(&self) -> Vec { -// call_method!(self, modified_data_ids) -// } -// } 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 cbd28a7d90..39d0c5e2ff 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 @@ -16,6 +16,7 @@ pub mod multi_party_action; mod resolvers; pub mod token_base_transition; pub mod token_burn_transition; +pub mod token_config_update_transition; pub mod token_destroy_frozen_funds_transition; pub mod token_emergency_action_transition; pub mod token_freeze_transition; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/mod.rs new file mode 100644 index 0000000000..f9e937cb3d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/mod.rs @@ -0,0 +1,25 @@ +pub mod v0; +mod v0_methods; + +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +pub use v0::TokenConfigUpdateTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenConfigUpdateTransition { + #[display("V0({})", "_0")] + V0(TokenConfigUpdateTransitionV0), +} + +impl Default for TokenConfigUpdateTransition { + fn default() -> Self { + TokenConfigUpdateTransition::V0(TokenConfigUpdateTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0/mod.rs new file mode 100644 index 0000000000..e49ba00050 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0/mod.rs @@ -0,0 +1,27 @@ +pub mod v0_methods; + +/// The Identifier fields in [`TokenConfigUpdateTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode::{Decode, Encode}; +use derive_more::Display; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display("Base: {base}, change: {update_token_configuration_item}")] +pub struct TokenConfigUpdateTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + /// Updated token configuration item + pub update_token_configuration_item: TokenConfigurationChangeItem, + /// The public note + pub public_note: Option, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..49ba01f625 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0/v0_methods.rs @@ -0,0 +1,87 @@ +use platform_value::Identifier; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +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_config_update_transition::TokenConfigUpdateTransitionV0; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenConfigUpdateTransitionV0 { + fn base(&self) -> &TokenBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: TokenBaseTransition) { + self.base = base; + } +} + +pub trait TokenConfigUpdateTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + /// Returns the `update_token_configuration_item` + fn update_token_configuration_item(&self) -> &TokenConfigurationChangeItem; + + /// Sets the `update_token_configuration_item` + fn set_update_token_configuration_item( + &mut self, + update_token_configuration_item: TokenConfigurationChangeItem, + ); + + /// Returns the `public_note` field of the `TokenConfigUpdateTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenConfigUpdateTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the `public_note` field in the `TokenConfigUpdateTransitionV0`. + fn set_public_note(&mut self, public_note: Option); +} + +impl TokenConfigUpdateTransitionV0Methods for TokenConfigUpdateTransitionV0 { + fn update_token_configuration_item(&self) -> &TokenConfigurationChangeItem { + &self.update_token_configuration_item + } + + fn set_update_token_configuration_item( + &mut self, + update_token_configuration_item: TokenConfigurationChangeItem, + ) { + self.update_token_configuration_item = update_token_configuration_item; + } + + fn public_note(&self) -> Option<&String> { + self.public_note.as_ref() + } + + fn public_note_owned(self) -> Option { + self.public_note + } + + fn set_public_note(&mut self, public_note: Option) { + self.public_note = public_note; + } +} + +impl AllowedAsMultiPartyAction for TokenConfigUpdateTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenConfigUpdateTransitionV0 { + base, + update_token_configuration_item, + .. + } = self; + + let mut bytes = b"action_token_config_update".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(&[update_token_configuration_item.u8_item_index()]); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0_methods.rs new file mode 100644 index 0000000000..b996f9a0b5 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_config_update_transition/v0_methods.rs @@ -0,0 +1,72 @@ +use platform_value::Identifier; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +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_config_update_transition::TokenConfigUpdateTransition; +use crate::state_transition::batch_transition::token_config_update_transition::v0::v0_methods::TokenConfigUpdateTransitionV0Methods; + +impl TokenBaseTransitionAccessors for TokenConfigUpdateTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenConfigUpdateTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenConfigUpdateTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenConfigUpdateTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenConfigUpdateTransitionV0Methods for TokenConfigUpdateTransition { + fn update_token_configuration_item(&self) -> &TokenConfigurationChangeItem { + match self { + TokenConfigUpdateTransition::V0(v0) => v0.update_token_configuration_item(), + } + } + + fn set_update_token_configuration_item( + &mut self, + update_token_configuration_item: TokenConfigurationChangeItem, + ) { + match self { + TokenConfigUpdateTransition::V0(v0) => { + v0.set_update_token_configuration_item(update_token_configuration_item) + } + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenConfigUpdateTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenConfigUpdateTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenConfigUpdateTransition::V0(v0) => v0.set_public_note(public_note), + } + } +} + +impl AllowedAsMultiPartyAction for TokenConfigUpdateTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenConfigUpdateTransition::V0(v0) => v0.calculate_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 91371bde32..5bf04af790 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 @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use platform_value::Identifier; use bincode::{Encode, Decode}; use data_contracts::SystemDataContract; +use platform_version::version::PlatformVersion; use crate::balances::credits::TokenAmount; use crate::block::block_info::BlockInfo; use crate::data_contract::accessors::v0::DataContractV0Getters; @@ -14,7 +15,7 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::Document; use crate::prelude::IdentityNonce; use crate::ProtocolError; -use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenTransferTransition}; +use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenConfigUpdateTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenTransferTransition}; use crate::state_transition::batch_transition::batched_transition::{DocumentPurchaseTransition, DocumentTransferTransition}; use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; use crate::state_transition::batch_transition::batched_transition::token_unfreeze_transition::TokenUnfreezeTransition; @@ -23,6 +24,7 @@ use crate::state_transition::batch_transition::token_base_transition::token_base 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::v0::v0_methods::TokenBurnTransitionV0Methods; +use crate::state_transition::batch_transition::token_config_update_transition::v0::v0_methods::TokenConfigUpdateTransitionV0Methods; use crate::state_transition::batch_transition::token_destroy_frozen_funds_transition::v0::v0_methods::TokenDestroyFrozenFundsTransitionV0Methods; use crate::state_transition::batch_transition::token_emergency_action_transition::v0::v0_methods::TokenEmergencyActionTransitionV0Methods; use crate::state_transition::batch_transition::token_freeze_transition::v0::v0_methods::TokenFreezeTransitionV0Methods; @@ -57,6 +59,9 @@ pub enum TokenTransition { #[display("TokenEmergencyActionTransition({})", "_0")] EmergencyAction(TokenEmergencyActionTransition), + + #[display("TokenConfigUpdateTransition({})", "_0")] + ConfigUpdate(TokenConfigUpdateTransition), } impl BatchTransitionResolversV0 for TokenTransition { @@ -185,6 +190,7 @@ pub trait TokenTransitionV0Methods { owner_nonce: IdentityNonce, block_info: &BlockInfo, token_configuration: &TokenConfiguration, + platform_version: &PlatformVersion, ) -> Result; } @@ -198,6 +204,7 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Unfreeze(t) => t.base(), TokenTransition::DestroyFrozenFunds(t) => t.base(), TokenTransition::EmergencyAction(t) => t.base(), + TokenTransition::ConfigUpdate(t) => t.base(), } } @@ -210,6 +217,7 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Unfreeze(t) => t.base_mut(), TokenTransition::DestroyFrozenFunds(t) => t.base_mut(), TokenTransition::EmergencyAction(t) => t.base_mut(), + TokenTransition::ConfigUpdate(t) => t.base_mut(), } } @@ -226,6 +234,7 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Transfer(_) => None, TokenTransition::DestroyFrozenFunds(t) => Some(t.calculate_action_id(owner_id)), TokenTransition::EmergencyAction(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::ConfigUpdate(t) => Some(t.calculate_action_id(owner_id)), } } @@ -236,7 +245,8 @@ impl TokenTransitionV0Methods for TokenTransition { | TokenTransition::Freeze(_) | TokenTransition::Unfreeze(_) | TokenTransition::DestroyFrozenFunds(_) - | TokenTransition::EmergencyAction(_) => true, + | TokenTransition::EmergencyAction(_) + | TokenTransition::ConfigUpdate(_) => true, TokenTransition::Transfer(_) => false, } } @@ -271,6 +281,7 @@ impl TokenTransitionV0Methods for TokenTransition { TokenTransition::Unfreeze(_) => "unfreeze", TokenTransition::EmergencyAction(_) => "emergencyAction", TokenTransition::DestroyFrozenFunds(_) => "destroyFrozenFunds", + TokenTransition::ConfigUpdate(_) => "configUpdate", } } @@ -306,6 +317,7 @@ impl TokenTransitionV0Methods for TokenTransition { owner_nonce: IdentityNonce, block_info: &BlockInfo, token_configuration: &TokenConfiguration, + platform_version: &PlatformVersion, ) -> Result { self.associated_token_event(token_configuration)? .build_historical_document_owned( @@ -314,6 +326,7 @@ impl TokenTransitionV0Methods for TokenTransition { owner_id, owner_nonce, block_info, + platform_version, ) } @@ -353,13 +366,17 @@ impl TokenTransitionV0Methods for TokenTransition { emergency_action.emergency_action(), emergency_action.public_note().cloned(), ), - TokenTransition::DestroyFrozenFunds(destroy) => { + TokenTransition::DestroyFrozenFunds(destroy_frozen_funds) => { TokenEvent::DestroyFrozenFunds( - destroy.frozen_identity_id(), + destroy_frozen_funds.frozen_identity_id(), TokenAmount::MAX, // we do not know how much will be destroyed - destroy.public_note().cloned(), + destroy_frozen_funds.public_note().cloned(), ) } + TokenTransition::ConfigUpdate(config_update) => TokenEvent::ConfigUpdate( + config_update.update_token_configuration_item().clone(), + config_update.public_note().cloned(), + ), }) } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs index d196637391..818c492021 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs @@ -12,6 +12,7 @@ pub enum TokenTransitionActionType { Unfreeze, DestroyFrozenFunds, EmergencyAction, + ConfigUpdate, } impl fmt::Display for TokenTransitionActionType { @@ -24,6 +25,7 @@ impl fmt::Display for TokenTransitionActionType { TokenTransitionActionType::Unfreeze => "Unfreeze", TokenTransitionActionType::DestroyFrozenFunds => "DestroyFrozenFunds", TokenTransitionActionType::EmergencyAction => "EmergencyAction", + TokenTransitionActionType::ConfigUpdate => "ConfigUpdate", }; write!(f, "{}", action_str) } @@ -43,6 +45,7 @@ impl TokenTransitionActionTypeGetter for TokenTransition { TokenTransition::Unfreeze(_) => TokenTransitionActionType::Unfreeze, TokenTransition::DestroyFrozenFunds(_) => TokenTransitionActionType::DestroyFrozenFunds, TokenTransition::EmergencyAction(_) => TokenTransitionActionType::EmergencyAction, + TokenTransition::ConfigUpdate(_) => TokenTransitionActionType::ConfigUpdate, } } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs index f690b7edc2..a92bc453fb 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs @@ -28,6 +28,7 @@ use crate::state_transition::batch_transition::BatchTransition; use crate::state_transition::batch_transition::{BatchTransitionV0, BatchTransitionV1}; #[cfg(feature = "state-transition-signing")] use crate::state_transition::StateTransition; +#[cfg(feature = "state-transition-signing")] use crate::tokens::emergency_action::TokenEmergencyAction; use crate::ProtocolError; #[cfg(feature = "state-transition-signing")] diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v1/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v1/mod.rs index db4e2efab7..ea9c43e7d4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v1/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v1/mod.rs @@ -1,17 +1,28 @@ +#[cfg(feature = "state-transition-signing")] use crate::balances::credits::TokenAmount; +#[cfg(feature = "state-transition-signing")] use crate::group::GroupStateTransitionInfoStatus; +#[cfg(feature = "state-transition-signing")] use crate::identity::signer::Signer; +#[cfg(feature = "state-transition-signing")] use crate::identity::IdentityPublicKey; +#[cfg(feature = "state-transition-signing")] use crate::prelude::{ DerivationEncryptionKeyIndex, IdentityNonce, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex, UserFeeIncrease, }; use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +#[cfg(feature = "state-transition-signing")] use crate::state_transition::StateTransition; +#[cfg(feature = "state-transition-signing")] use crate::tokens::emergency_action::TokenEmergencyAction; +#[cfg(feature = "state-transition-signing")] use crate::version::FeatureVersion; +#[cfg(feature = "state-transition-signing")] use crate::ProtocolError; +#[cfg(feature = "state-transition-signing")] use platform_value::Identifier; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; pub trait DocumentsBatchTransitionMethodsV1: DocumentsBatchTransitionAccessorsV0 { 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 a3600a133c..4b33e2e79e 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,6 +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_config_update_transition, token_config_update_transition::TokenConfigUpdateTransition, token_destroy_frozen_funds_transition, token_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransition, token_emergency_action_transition, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs index 91d9120c44..0ae1f0abcc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs @@ -7,13 +7,14 @@ use crate::fee::Credits; use crate::identity::signer::Signer; #[cfg(feature = "state-transition-signing")] use crate::identity::SecurityLevel; +use crate::prelude::IdentityNonce; #[cfg(feature = "state-transition-signing")] use crate::prelude::IdentityPublicKey; #[cfg(feature = "state-transition-signing")] use crate::prelude::UserFeeIncrease; +#[cfg(feature = "state-transition-signing")] use crate::prelude::{ - DerivationEncryptionKeyIndex, IdentityNonce, RecipientKeyIndex, RootEncryptionKeyIndex, - SenderKeyIndex, + DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex, }; use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; use crate::state_transition::batch_transition::batched_transition::{ diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs index c90794beb7..fa69e5a93f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs @@ -152,6 +152,7 @@ impl BatchTransition { TokenTransition::Unfreeze(_) => {} TokenTransition::DestroyFrozenFunds(_) => {} TokenTransition::EmergencyAction(_) => {} + TokenTransition::ConfigUpdate(_) => {} } // We need to verify that the action id given matches the expected action id diff --git a/packages/rs-dpp/src/tokens/token_event.rs b/packages/rs-dpp/src/tokens/token_event.rs index c0313efaee..dd13b2fe9e 100644 --- a/packages/rs-dpp/src/tokens/token_event.rs +++ b/packages/rs-dpp/src/tokens/token_event.rs @@ -1,6 +1,7 @@ use crate::balances::credits::TokenAmount; use crate::block::block_info::BlockInfo; use crate::data_contract::accessors::v0::DataContractV0Getters; +use crate::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0}; use crate::prelude::{ @@ -10,6 +11,7 @@ use crate::prelude::{ use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; +use platform_version::version::PlatformVersion; use std::collections::BTreeMap; pub type TokenEventPublicNote = Option; @@ -19,6 +21,7 @@ pub type TokenEventPersonalEncryptedNote = Option<( DerivationEncryptionKeyIndex, Vec, )>; +use crate::serialization::PlatformSerializableWithPlatformVersion; use crate::tokens::emergency_action::TokenEmergencyAction; use crate::ProtocolError; @@ -43,6 +46,7 @@ pub enum TokenEvent { TokenAmount, ), EmergencyAction(TokenEmergencyAction, TokenEventPublicNote), + ConfigUpdate(TokenConfigurationChangeItem, TokenEventPublicNote), } impl TokenEvent { @@ -55,6 +59,7 @@ impl TokenEvent { TokenEvent::DestroyFrozenFunds(_, _, _) => "destroyFrozenFunds", TokenEvent::Transfer(_, _, _, _, _) => "transfer", TokenEvent::EmergencyAction(_, _) => "emergencyAction", + TokenEvent::ConfigUpdate(_, _) => "configUpdate", } } @@ -72,6 +77,7 @@ impl TokenEvent { owner_id: Identifier, owner_nonce: IdentityNonce, block_info: &BlockInfo, + platform_version: &PlatformVersion, ) -> Result { let document_id = Document::generate_document_id_v0( &token_history_contract.id(), @@ -181,6 +187,25 @@ impl TokenEvent { } properties } + TokenEvent::ConfigUpdate(configuration_change_item, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ( + "changeItemType".to_string(), + configuration_change_item.u8_item_index().into(), + ), + ( + "changeItem".to_string(), + configuration_change_item + .serialize_consume_to_bytes_with_platform_version(platform_version)? + .into(), + ), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } }; let document: Document = DocumentV0 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/mod.rs similarity index 91% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/mod.rs index 56c8458ced..f238dd8633 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/mod.rs @@ -8,9 +8,9 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_create_transition_action::state_v0::DocumentCreateTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::document_create_transition_action::state_v1::DocumentCreateTransitionActionStateValidationV1; -use crate::execution::validation::state_transition::batch::action_validation::document_create_transition_action::structure_v0::DocumentCreateTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::state_v0::DocumentCreateTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::state_v1::DocumentCreateTransitionActionStateValidationV1; +use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::structure_v0::DocumentCreateTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/state_v0/mod.rs similarity index 98% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/state_v0/mod.rs index aa752dc2fd..5b016084d4 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/state_v0/mod.rs @@ -23,7 +23,7 @@ use crate::execution::validation::state_transition::batch::state::v0::fetch_cont use crate::execution::validation::state_transition::batch::state::v0::fetch_documents::fetch_document_with_id; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentCreateTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentCreateTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/state_v1/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/state_v1/mod.rs similarity index 98% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/state_v1/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/state_v1/mod.rs index 14cb413f30..6bde962b05 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/state_v1/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/state_v1/mod.rs @@ -25,7 +25,7 @@ use crate::execution::validation::state_transition::batch::state::v0::fetch_cont use crate::execution::validation::state_transition::batch::state::v0::fetch_documents::{fetch_document_with_id, has_contested_document_with_document_id}; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentCreateTransitionActionStateValidationV1 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentCreateTransitionActionStateValidationV1 { fn validate_state_v1( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/structure_v0/mod.rs similarity index 97% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/structure_v0/mod.rs index 49b71dc021..d3c0d57b7d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_create_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_create_transition_action/structure_v0/mod.rs @@ -14,7 +14,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use dpp::version::PlatformVersion; use crate::error::Error; -pub(super) trait DocumentCreateTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentCreateTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, owner_id: Identifier, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/mod.rs index a3b7196204..4bc007486b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_delete_transition_action::state_v0::DocumentDeleteTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::document_delete_transition_action::structure_v0::DocumentDeleteTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_delete_transition_action::state_v0::DocumentDeleteTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_delete_transition_action::structure_v0::DocumentDeleteTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/state_v0/mod.rs similarity index 96% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/state_v0/mod.rs index 6ccb56aa5b..bd96ae4727 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/state_v0/mod.rs @@ -20,7 +20,7 @@ use crate::execution::types::state_transition_execution_context::{StateTransitio use crate::execution::validation::state_transition::batch::state::v0::fetch_documents::fetch_document_with_id; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentDeleteTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentDeleteTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/structure_v0/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/structure_v0/mod.rs index 347e495894..0a9cbfe892 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_delete_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_delete_transition_action/structure_v0/mod.rs @@ -8,7 +8,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use crate::error::Error; -pub(super) trait DocumentDeleteTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentDeleteTransitionActionStructureValidationV0 { fn validate_structure_v0(&self) -> Result; } impl DocumentDeleteTransitionActionStructureValidationV0 for DocumentDeleteTransitionAction { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/mod.rs index 8396ba0577..8b37d7ed40 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/mod.rs @@ -8,8 +8,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_purchase_transition_action::state_v0::DocumentPurchaseTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::document_purchase_transition_action::structure_v0::DocumentPurchaseTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_purchase_transition_action::state_v0::DocumentPurchaseTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_purchase_transition_action::structure_v0::DocumentPurchaseTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/state_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/state_v0/mod.rs index c5060437b7..9d7b5d884f 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/state_v0/mod.rs @@ -12,7 +12,7 @@ use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentPurchaseTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentPurchaseTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/structure_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/structure_v0/mod.rs index 5a77bd645b..7c65043d3e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_purchase_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_purchase_transition_action/structure_v0/mod.rs @@ -9,7 +9,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use dpp::version::PlatformVersion; use crate::error::Error; -pub(super) trait DocumentPurchaseTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentPurchaseTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/mod.rs index 6392eb6870..6419ff5811 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/mod.rs @@ -8,8 +8,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_replace_transition_action::state_v0::DocumentReplaceTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::document_replace_transition_action::structure_v0::DocumentReplaceTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_replace_transition_action::state_v0::DocumentReplaceTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_replace_transition_action::structure_v0::DocumentReplaceTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/state_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/state_v0/mod.rs index 01359fb61e..ef3e33ad72 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/state_v0/mod.rs @@ -12,7 +12,7 @@ use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentReplaceTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentReplaceTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/structure_v0/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/structure_v0/mod.rs index acb8488346..582db214f0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_replace_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_replace_transition_action/structure_v0/mod.rs @@ -8,7 +8,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use dpp::version::PlatformVersion; use crate::error::Error; -pub(super) trait DocumentReplaceTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentReplaceTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/mod.rs index 6a517d7140..d5df2e9b98 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/mod.rs @@ -8,8 +8,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_transfer_transition_action::state_v0::DocumentTransferTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::document_transfer_transition_action::structure_v0::DocumentTransferTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_transfer_transition_action::state_v0::DocumentTransferTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_transfer_transition_action::structure_v0::DocumentTransferTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/state_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/state_v0/mod.rs index 3a779e1302..51b68d3d3c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/state_v0/mod.rs @@ -12,7 +12,7 @@ use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentTransferTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentTransferTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/structure_v0/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/structure_v0/mod.rs index a8beba7bae..c8c27c4630 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_transfer_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_transfer_transition_action/structure_v0/mod.rs @@ -7,7 +7,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use dpp::version::PlatformVersion; use crate::error::Error; -pub(super) trait DocumentTransferTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentTransferTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/mod.rs index b541eb15e1..6b9dcdcfe7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/mod.rs @@ -8,8 +8,8 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_update_price_transition_action::state_v0::DocumentUpdatePriceTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::document_update_price_transition_action::structure_v0::DocumentUpdatePriceTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_update_price_transition_action::state_v0::DocumentUpdatePriceTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::document::document_update_price_transition_action::structure_v0::DocumentUpdatePriceTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/state_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/state_v0/mod.rs index 9dc2abd730..62e1ff3cbb 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/state_v0/mod.rs @@ -12,7 +12,7 @@ use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait DocumentUpdatePriceTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentUpdatePriceTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/structure_v0/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/structure_v0/mod.rs index 8635df40dd..c595dba491 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document_update_price_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/document_update_price_transition_action/structure_v0/mod.rs @@ -7,7 +7,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use dpp::version::PlatformVersion; use crate::error::Error; -pub(super) trait DocumentUpdatePriceTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait DocumentUpdatePriceTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/mod.rs new file mode 100644 index 0000000000..32c28c43fa --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/document/mod.rs @@ -0,0 +1,6 @@ +pub(crate) mod document_create_transition_action; +pub(crate) mod document_delete_transition_action; +pub(crate) mod document_purchase_transition_action; +pub(crate) mod document_replace_transition_action; +pub(crate) mod document_transfer_transition_action; +pub(crate) mod document_update_price_transition_action; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/mod.rs index f9872eec43..7a2f9c5eb0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/mod.rs @@ -1,14 +1,2 @@ -pub(crate) mod document_create_transition_action; -pub(crate) mod document_delete_transition_action; -pub(crate) mod document_purchase_transition_action; -pub(crate) mod document_replace_transition_action; -pub(crate) mod document_transfer_transition_action; -pub(crate) mod document_update_price_transition_action; -pub(crate) mod token_base_transition_action; -pub(crate) mod token_burn_transition_action; -pub(crate) mod token_destroy_frozen_funds_transition_action; -pub(crate) mod token_emergency_action_transition_action; -pub(crate) mod token_freeze_transition_action; -pub(crate) mod token_mint_transition_action; -pub(crate) mod token_transfer_transition_action; -pub(crate) mod token_unfreeze_transition_action; +pub(crate) mod document; +pub(crate) mod token; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs new file mode 100644 index 0000000000..7060861681 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/mod.rs @@ -0,0 +1,9 @@ +pub(crate) mod token_base_transition_action; +pub(crate) mod token_burn_transition_action; +pub(crate) mod token_config_update_transition_action; +pub(crate) mod token_destroy_frozen_funds_transition_action; +pub(crate) mod token_emergency_action_transition_action; +pub(crate) mod token_freeze_transition_action; +pub(crate) mod token_mint_transition_action; +pub(crate) mod token_transfer_transition_action; +pub(crate) mod token_unfreeze_transition_action; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/mod.rs new file mode 100644 index 0000000000..3ee470eb30 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/mod.rs @@ -0,0 +1,138 @@ +use std::collections::BTreeMap; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; +use dpp::data_contract::change_control_rules::ChangeControlRules; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; +use crate::error::Error; +use crate::error::execution::ExecutionError; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::state_v0::TokenBaseTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::structure_v0::TokenBaseTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenBaseTransitionActionValidation { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result; + + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; + + fn validate_group_action( + &self, + rules: &ChangeControlRules, + owner_id: Identifier, + contract_owner_id: Identifier, + main_control_group: Option, + groups: &BTreeMap, + action_type_string: String, + token_configuration: &TokenConfiguration, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl TokenBaseTransitionActionValidation for TokenBaseTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_base_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenBaseTransitionAction::validate_structure".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + fn validate_state( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_base_transition_state_validation + { + 0 => self.validate_state_v0( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenBaseTransitionAction::validate_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + fn validate_group_action( + &self, + rules: &ChangeControlRules, + owner_id: Identifier, + contract_owner_id: Identifier, + main_control_group: Option, + groups: &BTreeMap, + action_type_string: String, + token_configuration: &TokenConfiguration, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_base_transition_group_action_validation + { + 0 => self.validate_group_action_v0( + rules, + owner_id, + contract_owner_id, + main_control_group, + groups, + action_type_string, + token_configuration, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenBaseTransitionAction::validate_group_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/state_v0/mod.rs similarity index 61% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/state_v0/mod.rs index 7653477deb..ae145aeefd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/state_v0/mod.rs @@ -1,26 +1,27 @@ +use std::collections::BTreeMap; use dpp::block::block_info::BlockInfo; use dpp::consensus::ConsensusError; -use dpp::consensus::state::identity::RecipientIdentityDoesNotExistError; +use dpp::consensus::state::group::GroupActionAlreadySignedByIdentityError; use dpp::consensus::state::state_error::StateError; use dpp::consensus::state::token::UnauthorizedTokenActionError; -use dpp::data_contract::accessors::v0::DataContractV0Getters; -use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; -use dpp::multi_identity_events::ActionTaker; +use dpp::data_contract::change_control_rules::ChangeControlRules; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; use dpp::prelude::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::{TokenMintTransitionAction, TokenMintTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use drive::query::TransactionArg; -use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; use crate::error::Error; -use crate::execution::types::execution_operation::{RetrieveIdentityInfo, ValidationOperation}; +use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenMintTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenBaseTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -30,8 +31,19 @@ pub(super) trait TokenMintTransitionActionStateValidationV0 { transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result; + + fn validate_group_action_v0( + &self, + rules: &ChangeControlRules, + owner_id: Identifier, + contract_owner_id: Identifier, + main_control_group: Option, + groups: &BTreeMap, + action_type_string: String, + token_configuration: &TokenConfiguration, + ) -> Result; } -impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { +impl TokenBaseTransitionActionStateValidationV0 for TokenBaseTransitionAction { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -41,28 +53,50 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result { - let validation_result = self.base().validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )?; - if !validation_result.is_valid() { - return Ok(validation_result); + // We should start by validating that if we did not yet sign + if let Some(group_state_transition_resolved_info) = self.store_in_group() { + let (already_signed, cost) = platform.drive.fetch_action_id_has_signer_with_costs( + self.data_contract_id(), + group_state_transition_resolved_info.group_contract_position, + group_state_transition_resolved_info.action_id, + owner_id, + block_info, + transaction, + platform_version, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(cost)); + if already_signed { + // We already have signed this state transition group action + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError( + StateError::GroupActionAlreadySignedByIdentityError( + GroupActionAlreadySignedByIdentityError::new( + owner_id, + self.data_contract_id(), + group_state_transition_resolved_info.group_contract_position, + group_state_transition_resolved_info.action_id, + ), + ), + ), + )); + } } - // Let's first check to see if we are authorized to perform this action - let contract = &self.data_contract_fetch_info_ref().contract; - let token_configuration = contract.expected_token_configuration(self.token_position())?; - let rules = token_configuration.manual_minting_rules(); - let main_control_group = token_configuration - .main_control_group() - .map(|position| contract.expected_group(position)) - .transpose()?; + Ok(SimpleConsensusValidationResult::new()) + } - if let Some(resolved_group_info) = self.base().store_in_group() { + fn validate_group_action_v0( + &self, + rules: &ChangeControlRules, + owner_id: Identifier, + contract_owner_id: Identifier, + main_control_group: Option, + groups: &BTreeMap, + action_type_string: String, + token_configuration: &TokenConfiguration, + ) -> Result { + // We should start by validating that if we did not yet sign + if let Some(resolved_group_info) = self.store_in_group() { // We are trying to do a group action // We have already checked when converting into an action that we are a member of the Group // Now we need to just check that the group is the actual group set by the contract @@ -73,7 +107,7 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { UnauthorizedTokenActionError::new( self.token_id(), owner_id, - "mint".to_string(), + action_type_string, rules.authorized_to_make_change_action_takers().clone(), ), )), @@ -92,7 +126,7 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { UnauthorizedTokenActionError::new( self.token_id(), owner_id, - "mint".to_string(), + action_type_string, rules.authorized_to_make_change_action_takers().clone(), ), ), @@ -108,7 +142,7 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { UnauthorizedTokenActionError::new( self.token_id(), owner_id, - "mint".to_string(), + action_type_string, rules.authorized_to_make_change_action_takers().clone(), ), )), @@ -118,17 +152,18 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { } } else { if !rules.can_make_change( - &contract.owner_id(), + &contract_owner_id, main_control_group, - contract.groups(), + groups, &ActionTaker::SingleIdentity(owner_id), + ActionGoal::ActionCompletion, ) { return Ok(SimpleConsensusValidationResult::new_with_error( ConsensusError::StateError(StateError::UnauthorizedTokenActionError( UnauthorizedTokenActionError::new( self.token_id(), owner_id, - "mint".to_string(), + action_type_string, rules.authorized_to_make_change_action_takers().clone(), ), )), @@ -136,31 +171,6 @@ impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { } } - // todo verify that minting would not break max supply - - // We need to verify that the receiver is a valid identity - - let recipient = self.identity_balance_holder_id(); - if recipient != owner_id { - // We have already checked that this user exists if the recipient is the owner id - let balance = platform.drive.fetch_identity_balance( - recipient.to_buffer(), - transaction, - platform_version, - )?; - execution_context.add_operation(ValidationOperation::RetrieveIdentity( - RetrieveIdentityInfo::only_balance(), - )); - if balance.is_none() { - // The identity does not exist - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError(StateError::RecipientIdentityDoesNotExistError( - RecipientIdentityDoesNotExistError::new(recipient), - )), - )); - } - } - Ok(SimpleConsensusValidationResult::new()) } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/structure_v0/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/structure_v0/mod.rs index 034d208c51..3fb19707d4 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_base_transition_action/structure_v0/mod.rs @@ -8,7 +8,7 @@ use drive::state_transition_action::batch::batched_transition::token_transition: use dpp::version::PlatformVersion; use crate::error::Error; -pub(super) trait TokenBaseTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenBaseTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/mod.rs index 0ed8bdfb4d..e92feab605 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_burn_transition_action::state_v0::TokenBurnTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_burn_transition_action::structure_v0::TokenBurnTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_burn_transition_action::state_v0::TokenBurnTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_burn_transition_action::structure_v0::TokenBurnTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/state_v0/mod.rs similarity index 79% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/state_v0/mod.rs index 85ad0983ef..ae67c64bdf 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/state_v0/mod.rs @@ -5,19 +5,21 @@ use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, U use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::multi_identity_events::ActionTaker; +use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; use dpp::prelude::Identifier; use dpp::validation::SimpleConsensusValidationResult; use drive::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::{TokenBurnTransitionAction, TokenBurnTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; use crate::error::Error; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenBurnTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenBurnTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -54,27 +56,20 @@ impl TokenBurnTransitionActionStateValidationV0 for TokenBurnTransitionAction { let contract = &self.data_contract_fetch_info_ref().contract; let token_configuration = contract.expected_token_configuration(self.token_position())?; let rules = token_configuration.manual_burning_rules(); - let main_control_group = token_configuration - .main_control_group() - .map(|position| contract.expected_group(position)) - .transpose()?; - if !rules.can_make_change( - &contract.owner_id(), + let main_control_group = token_configuration.main_control_group(); + let validation_result = self.base().validate_group_action( + rules, + owner_id, + contract.owner_id(), main_control_group, contract.groups(), - &ActionTaker::SingleIdentity(owner_id), - ) { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError(StateError::UnauthorizedTokenActionError( - UnauthorizedTokenActionError::new( - self.token_id(), - owner_id, - "burn".to_string(), - rules.authorized_to_make_change_action_takers().clone(), - ), - )), - )); + "burn".to_string(), + token_configuration, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); } // We need to verify that we have enough of the token diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/structure_v0/mod.rs similarity index 80% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/structure_v0/mod.rs index 3529a60558..440d14ec86 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_burn_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::{TokenBurnTransitionAction, TokenBurnTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenBurnTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenBurnTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/mod.rs similarity index 76% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/mod.rs index ed77bb370d..8dc9777366 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/mod.rs @@ -1,20 +1,20 @@ use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::TokenConfigUpdateTransitionAction; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::state_v0::TokenBaseTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::structure_v0::TokenBaseTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_config_update_transition_action::state_v0::TokenConfigUpdateTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_config_update_transition_action::structure_v0::TokenConfigUpdateTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; mod structure_v0; -pub trait TokenBaseTransitionActionValidation { +pub trait TokenConfigUpdateTransitionActionValidation { fn validate_structure( &self, platform_version: &PlatformVersion, @@ -31,7 +31,7 @@ pub trait TokenBaseTransitionActionValidation { ) -> Result; } -impl TokenBaseTransitionActionValidation for TokenBaseTransitionAction { +impl TokenConfigUpdateTransitionActionValidation for TokenConfigUpdateTransitionAction { fn validate_structure( &self, platform_version: &PlatformVersion, @@ -41,11 +41,11 @@ impl TokenBaseTransitionActionValidation for TokenBaseTransitionAction { .validation_and_processing .state_transitions .batch_state_transition - .token_base_transition_structure_validation + .token_config_update_transition_structure_validation { 0 => self.validate_structure_v0(platform_version), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { - method: "TokenBaseTransitionAction::validate_structure".to_string(), + method: "TokenConfigUpdateTransitionAction::validate_structure".to_string(), known_versions: vec![0], received: version, })), @@ -66,7 +66,7 @@ impl TokenBaseTransitionActionValidation for TokenBaseTransitionAction { .validation_and_processing .state_transitions .batch_state_transition - .token_base_transition_structure_validation + .token_config_update_transition_state_validation { 0 => self.validate_state_v0( platform, @@ -77,7 +77,7 @@ impl TokenBaseTransitionActionValidation for TokenBaseTransitionAction { platform_version, ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { - method: "TokenBaseTransitionAction::validate_state".to_string(), + method: "TokenConfigUpdateTransitionAction::validate_state".to_string(), known_versions: vec![0], received: version, })), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..c4aec5e98f --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/state_v0/mod.rs @@ -0,0 +1,81 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::UnauthorizedTokenActionError; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; +use dpp::prelude::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::{TokenConfigUpdateTransitionAction, TokenConfigUpdateTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext}; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenConfigUpdateTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenConfigUpdateTransitionActionStateValidationV0 for TokenConfigUpdateTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // Let's first check to see if we are authorized to perform this action + let contract = &self.data_contract_fetch_info_ref().contract; + let token_configuration = contract.expected_token_configuration(self.token_position())?; + let main_control_group = token_configuration.main_control_group(); + + if !token_configuration.can_apply_token_configuration_item( + self.update_token_configuration_item(), + &contract.owner_id(), + main_control_group, + contract.groups(), + &ActionTaker::SingleIdentity(owner_id), + ActionGoal::ActionParticipation, + ) { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::UnauthorizedTokenActionError( + UnauthorizedTokenActionError::new( + self.token_id(), + owner_id, + "config_update".to_string(), + token_configuration.authorized_action_takers_for_configuration_item( + self.update_token_configuration_item(), + ), + ), + )), + )); + } + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..604c50480b --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_config_update_transition_action/structure_v0/mod.rs @@ -0,0 +1,25 @@ +use dpp::validation::{SimpleConsensusValidationResult}; +use drive::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::{TokenConfigUpdateTransitionAction, TokenConfigUpdateTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use crate::error::Error; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenConfigUpdateTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenConfigUpdateTransitionActionStructureValidationV0 for TokenConfigUpdateTransitionAction { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_structure(platform_version)?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + Ok(SimpleConsensusValidationResult::default()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/mod.rs index 9b8428f51d..513913539b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_destroy_frozen_funds_transition_action::state_v0::TokenDestroyFrozenFundsTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_destroy_frozen_funds_transition_action::structure_v0::TokenDestroyFrozenFundsTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_destroy_frozen_funds_transition_action::state_v0::TokenDestroyFrozenFundsTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_destroy_frozen_funds_transition_action::structure_v0::TokenDestroyFrozenFundsTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/state_v0/mod.rs similarity index 79% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/state_v0/mod.rs index 99bf2b350c..b37bfab734 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/state_v0/mod.rs @@ -5,7 +5,7 @@ use dpp::consensus::state::token::{IdentityTokenAccountNotFrozenError, Unauthori use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::multi_identity_events::ActionTaker; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; use dpp::prelude::Identifier; use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; use dpp::validation::SimpleConsensusValidationResult; @@ -15,10 +15,10 @@ use drive::query::TransactionArg; use crate::error::Error; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenDestroyFrozenFundsTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenDestroyFrozenFundsTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -81,27 +81,19 @@ impl TokenDestroyFrozenFundsTransitionActionStateValidationV0 let contract = &self.data_contract_fetch_info_ref().contract; let token_configuration = contract.expected_token_configuration(self.token_position())?; let rules = token_configuration.destroy_frozen_funds_rules(); - let main_control_group = token_configuration - .main_control_group() - .map(|position| contract.expected_group(position)) - .transpose()?; - - if !rules.can_make_change( - &contract.owner_id(), + let main_control_group = token_configuration.main_control_group(); + let validation_result = self.base().validate_group_action( + rules, + owner_id, + contract.owner_id(), main_control_group, contract.groups(), - &ActionTaker::SingleIdentity(owner_id), - ) { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError(StateError::UnauthorizedTokenActionError( - UnauthorizedTokenActionError::new( - self.token_id(), - owner_id, - "destroy_frozen_funds".to_string(), - rules.authorized_to_make_change_action_takers().clone(), - ), - )), - )); + "destroy frozen funds".to_string(), + token_configuration, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); } Ok(SimpleConsensusValidationResult::new()) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs similarity index 80% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs index 2f0c22d417..3553718572 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::{TokenDestroyFrozenFundsTransitionAction, TokenDestroyFrozenFundsTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenDestroyFrozenFundsTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenDestroyFrozenFundsTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/mod.rs index a78f9e9537..074b2f59f1 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_emergency_action_transition_action::state_v0::TokenEmergencyActionTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_emergency_action_transition_action::structure_v0::TokenEmergencyActionTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_emergency_action_transition_action::state_v0::TokenEmergencyActionTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_emergency_action_transition_action::structure_v0::TokenEmergencyActionTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/state_v0/mod.rs similarity index 72% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/state_v0/mod.rs index c5ea53f9b0..928e9f092b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/state_v0/mod.rs @@ -5,7 +5,7 @@ use dpp::consensus::state::token::UnauthorizedTokenActionError; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::multi_identity_events::ActionTaker; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; use dpp::prelude::Identifier; use dpp::validation::SimpleConsensusValidationResult; use drive::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::{TokenEmergencyActionTransitionAction, TokenEmergencyActionTransitionActionAccessorsV0}; @@ -13,10 +13,10 @@ use dpp::version::PlatformVersion; use drive::query::TransactionArg; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenEmergencyActionTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenEmergencyActionTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -55,27 +55,19 @@ impl TokenEmergencyActionTransitionActionStateValidationV0 let contract = &self.data_contract_fetch_info_ref().contract; let token_configuration = contract.expected_token_configuration(self.token_position())?; let rules = token_configuration.emergency_action_rules(); - let main_control_group = token_configuration - .main_control_group() - .map(|position| contract.expected_group(position)) - .transpose()?; - - if !rules.can_make_change( - &contract.owner_id(), + let main_control_group = token_configuration.main_control_group(); + let validation_result = self.base().validate_group_action( + rules, + owner_id, + contract.owner_id(), main_control_group, contract.groups(), - &ActionTaker::SingleIdentity(owner_id), - ) { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError(StateError::UnauthorizedTokenActionError( - UnauthorizedTokenActionError::new( - self.token_id(), - owner_id, - "emergency_action".to_string(), - rules.authorized_to_make_change_action_takers().clone(), - ), - )), - )); + "emergency action".to_string(), + token_configuration, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); } Ok(SimpleConsensusValidationResult::new()) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/structure_v0/mod.rs similarity index 80% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/structure_v0/mod.rs index cc4f6b8d25..e89432925e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_emergency_action_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::{TokenEmergencyActionTransitionAction, TokenEmergencyActionTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenEmergencyActionTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenEmergencyActionTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/mod.rs index 47777b8d73..a832de4810 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_freeze_transition_action::state_v0::TokenFreezeTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_freeze_transition_action::structure_v0::TokenFreezeTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_freeze_transition_action::state_v0::TokenFreezeTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_freeze_transition_action::structure_v0::TokenFreezeTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/state_v0/mod.rs similarity index 72% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/state_v0/mod.rs index 507f02c281..69333fa12d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/state_v0/mod.rs @@ -5,7 +5,7 @@ use dpp::consensus::state::token::UnauthorizedTokenActionError; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::multi_identity_events::ActionTaker; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; use dpp::prelude::Identifier; use dpp::validation::SimpleConsensusValidationResult; use drive::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::{TokenFreezeTransitionAction, TokenFreezeTransitionActionAccessorsV0}; @@ -13,10 +13,10 @@ use dpp::version::PlatformVersion; use drive::query::TransactionArg; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenFreezeTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenFreezeTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -53,27 +53,19 @@ impl TokenFreezeTransitionActionStateValidationV0 for TokenFreezeTransitionActio let contract = &self.data_contract_fetch_info_ref().contract; let token_configuration = contract.expected_token_configuration(self.token_position())?; let rules = token_configuration.freeze_rules(); - let main_control_group = token_configuration - .main_control_group() - .map(|position| contract.expected_group(position)) - .transpose()?; - - if !rules.can_make_change( - &contract.owner_id(), + let main_control_group = token_configuration.main_control_group(); + let validation_result = self.base().validate_group_action( + rules, + owner_id, + contract.owner_id(), main_control_group, contract.groups(), - &ActionTaker::SingleIdentity(owner_id), - ) { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError(StateError::UnauthorizedTokenActionError( - UnauthorizedTokenActionError::new( - self.token_id(), - owner_id, - "freeze".to_string(), - rules.authorized_to_make_change_action_takers().clone(), - ), - )), - )); + "freeze".to_string(), + token_configuration, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); } Ok(SimpleConsensusValidationResult::new()) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/structure_v0/mod.rs similarity index 80% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/structure_v0/mod.rs index 8b754e60e7..d2c641554c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_freeze_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::{TokenFreezeTransitionAction, TokenFreezeTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenFreezeTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenFreezeTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/mod.rs index f8cd83b7a6..56c8d556a7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_mint_transition_action::state_v0::TokenMintTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_mint_transition_action::structure_v0::TokenMintTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_mint_transition_action::state_v0::TokenMintTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_mint_transition_action::structure_v0::TokenMintTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..eba4356e11 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/state_v0/mod.rs @@ -0,0 +1,102 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::identity::RecipientIdentityDoesNotExistError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::UnauthorizedTokenActionError; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; +use dpp::prelude::Identifier; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::{TokenMintTransitionAction, TokenMintTransitionActionAccessorsV0}; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; +use crate::error::Error; +use crate::execution::types::execution_operation::{RetrieveIdentityInfo, ValidationOperation}; +use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenMintTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenMintTransitionActionStateValidationV0 for TokenMintTransitionAction { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let validation_result = self.base().validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // Let's first check to see if we are authorized to perform this action + let contract = &self.data_contract_fetch_info_ref().contract; + let token_configuration = contract.expected_token_configuration(self.token_position())?; + let rules = token_configuration.manual_minting_rules(); + let main_control_group = token_configuration.main_control_group(); + let validation_result = self.base().validate_group_action( + rules, + owner_id, + contract.owner_id(), + main_control_group, + contract.groups(), + "mint".to_string(), + token_configuration, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); + } + + // todo verify that minting would not break max supply + + // We need to verify that the receiver is a valid identity + + let recipient = self.identity_balance_holder_id(); + if recipient != owner_id { + // We have already checked that this user exists if the recipient is the owner id + let balance = platform.drive.fetch_identity_balance( + recipient.to_buffer(), + transaction, + platform_version, + )?; + execution_context.add_operation(ValidationOperation::RetrieveIdentity( + RetrieveIdentityInfo::only_balance(), + )); + if balance.is_none() { + // The identity does not exist + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::RecipientIdentityDoesNotExistError( + RecipientIdentityDoesNotExistError::new(recipient), + )), + )); + } + } + + Ok(SimpleConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/structure_v0/mod.rs similarity index 80% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/structure_v0/mod.rs index 33648a7e26..7eb4aab96d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_mint_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::{TokenMintTransitionAction, TokenMintTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenMintTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenMintTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/mod.rs index 2d9754412f..924b4b80a2 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_transfer_transition_action::state_v0::TokenTransferTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_transfer_transition_action::structure_v0::TokenTransferTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_transfer_transition_action::state_v0::TokenTransferTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_transfer_transition_action::structure_v0::TokenTransferTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs index 04336501c9..a40b0f3040 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/state_v0/mod.rs @@ -12,10 +12,10 @@ use drive::state_transition_action::batch::batched_transition::token_transition: use crate::error::Error; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenTransferTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenTransferTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/structure_v0/mod.rs similarity index 83% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/structure_v0/mod.rs index 92747e6d4f..2b0fc92e20 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_transfer_transition_action/structure_v0/mod.rs @@ -4,9 +4,9 @@ use drive::state_transition_action::batch::batched_transition::token_transition: use dpp::version::PlatformVersion; use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionAccessorsV0; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenTransferTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenTransferTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, owner_id: Identifier, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/mod.rs similarity index 93% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/mod.rs index 0cb5f563fc..293906e3f0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/mod.rs @@ -7,8 +7,8 @@ use drive::grovedb::TransactionArg; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::token_unfreeze_transition_action::state_v0::TokenUnfreezeTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::batch::action_validation::token_unfreeze_transition_action::structure_v0::TokenUnfreezeTransitionActionStructureValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_unfreeze_transition_action::state_v0::TokenUnfreezeTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token::token_unfreeze_transition_action::structure_v0::TokenUnfreezeTransitionActionStructureValidationV0; use crate::platform_types::platform::PlatformStateRef; mod state_v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/state_v0/mod.rs similarity index 79% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/state_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/state_v0/mod.rs index e8ba23d7f4..d99fab0765 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/state_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/state_v0/mod.rs @@ -5,7 +5,7 @@ use dpp::consensus::state::token::{IdentityTokenAccountNotFrozenError, Unauthori use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; -use dpp::multi_identity_events::ActionTaker; +use dpp::group::action_taker::{ActionGoal, ActionTaker}; use dpp::prelude::Identifier; use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; use dpp::validation::SimpleConsensusValidationResult; @@ -15,10 +15,10 @@ use drive::query::TransactionArg; use crate::error::Error; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; use crate::platform_types::platform::PlatformStateRef; -pub(super) trait TokenUnfreezeTransitionActionStateValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenUnfreezeTransitionActionStateValidationV0 { fn validate_state_v0( &self, platform: &PlatformStateRef, @@ -79,27 +79,19 @@ impl TokenUnfreezeTransitionActionStateValidationV0 for TokenUnfreezeTransitionA let contract = &self.data_contract_fetch_info_ref().contract; let token_configuration = contract.expected_token_configuration(self.token_position())?; let rules = token_configuration.unfreeze_rules(); - let main_control_group = token_configuration - .main_control_group() - .map(|position| contract.expected_group(position)) - .transpose()?; - - if !rules.can_make_change( - &contract.owner_id(), + let main_control_group = token_configuration.main_control_group(); + let validation_result = self.base().validate_group_action( + rules, + owner_id, + contract.owner_id(), main_control_group, contract.groups(), - &ActionTaker::SingleIdentity(owner_id), - ) { - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError(StateError::UnauthorizedTokenActionError( - UnauthorizedTokenActionError::new( - self.token_id(), - owner_id, - "unfreeze".to_string(), - rules.authorized_to_make_change_action_takers().clone(), - ), - )), - )); + "unfreeze".to_string(), + token_configuration, + platform_version, + )?; + if !validation_result.is_valid() { + return Ok(validation_result); } Ok(SimpleConsensusValidationResult::new()) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/structure_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/structure_v0/mod.rs similarity index 80% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/structure_v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/structure_v0/mod.rs index ba729c1f5e..f3a0b24e33 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/structure_v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token/token_unfreeze_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::validation::{SimpleConsensusValidationResult}; use drive::state_transition_action::batch::batched_transition::token_transition::token_unfreeze_transition_action::{TokenUnfreezeTransitionAction, TokenUnfreezeTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; -use crate::execution::validation::state_transition::batch::action_validation::token_base_transition_action::TokenBaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_base_transition_action::TokenBaseTransitionActionValidation; -pub(super) trait TokenUnfreezeTransitionActionStructureValidationV0 { +pub(in crate::execution::validation::state_transition::state_transitions::batch::action_validation) trait TokenUnfreezeTransitionActionStructureValidationV0 { fn validate_structure_v0( &self, platform_version: &PlatformVersion, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/state_v0/mod.rs deleted file mode 100644 index d072a906d3..0000000000 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/state_v0/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -use dpp::block::block_info::BlockInfo; -use dpp::consensus::ConsensusError; -use dpp::consensus::state::group::GroupActionAlreadySignedByIdentityError; -use dpp::consensus::state::state_error::StateError; -use dpp::prelude::Identifier; -use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; -use dpp::version::PlatformVersion; -use drive::query::TransactionArg; -use crate::error::Error; -use crate::execution::types::execution_operation::ValidationOperation; -use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::platform_types::platform::PlatformStateRef; - -pub(super) trait TokenBaseTransitionActionStateValidationV0 { - fn validate_state_v0( - &self, - platform: &PlatformStateRef, - owner_id: Identifier, - block_info: &BlockInfo, - execution_context: &mut StateTransitionExecutionContext, - transaction: TransactionArg, - platform_version: &PlatformVersion, - ) -> Result; -} -impl TokenBaseTransitionActionStateValidationV0 for TokenBaseTransitionAction { - fn validate_state_v0( - &self, - platform: &PlatformStateRef, - owner_id: Identifier, - block_info: &BlockInfo, - execution_context: &mut StateTransitionExecutionContext, - transaction: TransactionArg, - platform_version: &PlatformVersion, - ) -> Result { - // We should start by validating that if we did not yet sign - if let Some(group_state_transition_resolved_info) = self.store_in_group() { - let (already_signed, cost) = platform.drive.fetch_action_id_has_signer_with_costs( - self.data_contract_id(), - group_state_transition_resolved_info.group_contract_position, - group_state_transition_resolved_info.action_id, - owner_id, - block_info, - transaction, - platform_version, - )?; - execution_context.add_operation(ValidationOperation::PrecalculatedOperation(cost)); - if already_signed { - // We already have signed this state transition group action - return Ok(SimpleConsensusValidationResult::new_with_error( - ConsensusError::StateError( - StateError::GroupActionAlreadySignedByIdentityError( - GroupActionAlreadySignedByIdentityError::new( - owner_id, - self.data_contract_id(), - group_state_transition_resolved_info.group_contract_position, - group_state_transition_resolved_info.action_id, - ), - ), - ), - )); - } - } - - Ok(SimpleConsensusValidationResult::new()) - } -} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/v0/mod.rs index d4da544dc9..1147fa871c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/v0/mod.rs @@ -18,9 +18,9 @@ use dpp::validation::ConsensusValidationResult; use dpp::version::PlatformVersion; use drive::state_transition_action::batch::BatchTransitionAction; -use crate::execution::validation::state_transition::state_transitions::batch::action_validation::document_replace_transition_action::DocumentReplaceTransitionActionValidation; -use crate::execution::validation::state_transition::state_transitions::batch::action_validation::document_delete_transition_action::DocumentDeleteTransitionActionValidation; -use crate::execution::validation::state_transition::state_transitions::batch::action_validation::document_create_transition_action::DocumentCreateTransitionActionValidation; +use crate::execution::validation::state_transition::state_transitions::batch::action_validation::document::document_replace_transition_action::DocumentReplaceTransitionActionValidation; +use crate::execution::validation::state_transition::state_transitions::batch::action_validation::document::document_delete_transition_action::DocumentDeleteTransitionActionValidation; +use crate::execution::validation::state_transition::state_transitions::batch::action_validation::document::document_create_transition_action::DocumentCreateTransitionActionValidation; use dpp::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; use drive::state_transition_action::batch::batched_transition::BatchedTransitionAction; use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; @@ -29,6 +29,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use drive::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::DocumentTransferTransitionActionAccessorsV0; use drive::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionActionAccessorsV0; use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::TokenConfigUpdateTransitionActionAccessorsV0; use drive::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionAccessorsV0; use drive::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionAccessorsV0; use drive::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::TokenFreezeTransitionActionAccessorsV0; @@ -41,16 +42,17 @@ use drive::state_transition_action::system::bump_identity_data_contract_nonce_ac use crate::error::execution::ExecutionError; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; -use crate::execution::validation::state_transition::batch::action_validation::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_transfer_transition_action::DocumentTransferTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_burn_transition_action::TokenBurnTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_freeze_transition_action::TokenFreezeTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_mint_transition_action::TokenMintTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_transfer_transition_action::TokenTransferTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_unfreeze_transition_action::TokenUnfreezeTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_transfer_transition_action::DocumentTransferTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_burn_transition_action::TokenBurnTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_config_update_transition_action::TokenConfigUpdateTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_freeze_transition_action::TokenFreezeTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_mint_transition_action::TokenMintTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_transfer_transition_action::TokenTransferTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_unfreeze_transition_action::TokenUnfreezeTransitionActionValidation; pub(in crate::execution::validation::state_transition::state_transitions::batch) trait DocumentsBatchStateTransitionStructureValidationV0 { @@ -320,6 +322,19 @@ impl DocumentsBatchStateTransitionStructureValidationV0 for BatchTransition { BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(destroy_frozen_funds_action.base(), self.owner_id(), self.user_fee_increase()), ); + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::ConfigUpdateAction(config_update_action) => { + let result = config_update_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(config_update_action.base(), self.owner_id(), self.user_fee_increase()), + ); + return Ok(ConsensusValidationResult::new_with_data_and_errors( bump_action, result.errors, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs index 83ac4eb0f6..f20e61f03b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs @@ -11169,11 +11169,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::NoOne, - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -11274,11 +11273,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -11390,11 +11388,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -11502,11 +11499,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -11700,11 +11696,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -11908,11 +11903,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -12202,11 +12196,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -12495,11 +12488,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -12613,11 +12605,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -12816,11 +12807,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: - false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -13559,10 +13549,10 @@ mod tests { token_configuration.set_manual_minting_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::Group(0), - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -13773,10 +13763,10 @@ mod tests { token_configuration.set_freeze_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::ContractOwner, - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -13872,19 +13862,19 @@ mod tests { token_configuration.set_freeze_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::ContractOwner, - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); token_configuration.set_unfreeze_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::ContractOwner, - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), @@ -14042,19 +14032,19 @@ mod tests { token_configuration.set_freeze_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::ContractOwner, - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); token_configuration.set_unfreeze_rules(ChangeControlRules::V0( ChangeControlRulesV0 { authorized_to_make_change: AuthorizedActionTakers::ContractOwner, - authorized_to_change_authorized_action_takers: - AuthorizedActionTakers::NoOne, + admin_action_takers: AuthorizedActionTakers::NoOne, changing_authorized_action_takers_to_no_one_allowed: false, - changing_authorized_action_takers_to_contract_owner_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, }, )); }), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs index 5b225e70a7..6db47d9f74 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs @@ -15,19 +15,20 @@ use drive::state_transition_action::system::bump_identity_data_contract_nonce_ac use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::batch::action_validation::document_create_transition_action::DocumentCreateTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_delete_transition_action::DocumentDeleteTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_replace_transition_action::DocumentReplaceTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_transfer_transition_action::DocumentTransferTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_burn_transition_action::TokenBurnTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_freeze_transition_action::TokenFreezeTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_mint_transition_action::TokenMintTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_transfer_transition_action::TokenTransferTransitionActionValidation; -use crate::execution::validation::state_transition::batch::action_validation::token_unfreeze_transition_action::TokenUnfreezeTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_create_transition_action::DocumentCreateTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_delete_transition_action::DocumentDeleteTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_replace_transition_action::DocumentReplaceTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_transfer_transition_action::DocumentTransferTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::document::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_burn_transition_action::TokenBurnTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_config_update_transition_action::TokenConfigUpdateTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_freeze_transition_action::TokenFreezeTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_mint_transition_action::TokenMintTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_transfer_transition_action::TokenTransferTransitionActionValidation; +use crate::execution::validation::state_transition::batch::action_validation::token::token_unfreeze_transition_action::TokenUnfreezeTransitionActionValidation; use crate::execution::validation::state_transition::batch::data_triggers::{data_trigger_bindings_list, DataTriggerExecutionContext, DataTriggerExecutor}; use crate::platform_types::platform::{PlatformStateRef}; use crate::execution::validation::state_transition::state_transitions::batch::transformer::v0::BatchTransitionTransformerV0; @@ -208,6 +209,16 @@ impl DocumentsBatchStateTransitionStateValidationV0 for BatchTransition { transaction, platform_version, )?, + TokenTransitionAction::ConfigUpdateAction(config_update_action) => { + config_update_action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )? + } }, BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( 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 f9ed1d6d66..4828d923f8 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 @@ -55,6 +55,7 @@ use drive::state_transition_action::batch::batched_transition::document_transiti use drive::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; use drive::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::TokenBurnTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::TokenConfigUpdateTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::TokenEmergencyActionTransitionAction; use drive::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::TokenFreezeTransitionAction; @@ -573,6 +574,16 @@ impl BatchTransitionInternalTransformerV0 for BatchTransition { Ok(data_contract_fetch_info.clone()) }, platform_version)?; + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + Ok(batched_action) + } + TokenTransition::ConfigUpdate(token_config_update) => { + let (batched_action, fee_result) = TokenConfigUpdateTransitionAction::try_from_borrowed_token_config_update_transition_with_contract_lookup(drive, owner_id, token_config_update, approximate_for_costs, transaction, block_info, user_fee_increase, |_identifier| { + Ok(data_contract_fetch_info.clone()) + }, platform_version)?; + execution_context .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs index 6d81da251c..f4ca13d3a2 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/advanced_structure/v0/mod.rs @@ -14,11 +14,12 @@ use dpp::prelude::DataContract; use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; use dpp::validation::ConsensusValidationResult; +use dpp::version::PlatformVersion; use drive::state_transition_action::system::bump_identity_nonce_action::BumpIdentityNonceAction; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::data_contract_create) trait DataContractCreatedStateTransitionAdvancedStructureValidationV0 { - fn validate_advanced_structure_v0(&self, execution_context: &mut StateTransitionExecutionContext) -> Result, Error>; + fn validate_advanced_structure_v0(&self, execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion) -> Result, Error>; } impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 @@ -27,6 +28,7 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 fn validate_advanced_structure_v0( &self, execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, ) -> Result, Error> { if self.data_contract().version() != INITIAL_DATA_CONTRACT_VERSION { let bump_action = StateTransitionAction::BumpIdentityNonceAction( @@ -69,6 +71,22 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 )); } + let groups = self.data_contract().groups(); + if !groups.is_empty() { + let validation_result = DataContract::validate_groups(groups, platform_version)?; + + if !validation_result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityNonceAction( + BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + validation_result.errors, + )); + } + } + let expected_position = 0; for (token_contract_position, token_configuration) in self.data_contract().tokens() { @@ -99,6 +117,21 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 ], )); } + + let validation_result = token_configuration.validate_token_config_groups_exist( + self.data_contract().groups(), + platform_version, + )?; + if !validation_result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityNonceAction( + BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + validation_result.errors, + )); + } } Ok(ConsensusValidationResult::default()) @@ -152,7 +185,7 @@ mod tests { .expect("failed to create execution context"); let result = transition - .validate_advanced_structure_v0(&mut execution_context) + .validate_advanced_structure_v0(&mut execution_context, platform_version) .expect("failed to validate advanced structure"); assert_matches!(execution_context.operations_slice(), []); @@ -202,7 +235,7 @@ mod tests { .expect("failed to create execution context"); let result = transition - .validate_advanced_structure_v0(&mut execution_context) + .validate_advanced_structure_v0(&mut execution_context, platform_version) .expect("failed to validate advanced structure"); assert_matches!( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs index a5a0983202..e2cef7ac75 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs @@ -85,7 +85,7 @@ impl StateTransitionAdvancedStructureValidationV0 for DataContractCreateTransiti .contract_create_state_transition .basic_structure { - Some(0) => self.validate_advanced_structure_v0(execution_context), + Some(0) => self.validate_advanced_structure_v0(execution_context, platform_version), Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "data contract create transition: validate_basic_structure".to_string(), known_versions: vec![0], @@ -151,6 +151,11 @@ mod tests { use dpp::dash_to_credits; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Setters; + use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; + use dpp::data_contract::change_control_rules::v0::ChangeControlRulesV0; + use dpp::data_contract::change_control_rules::ChangeControlRules; + use dpp::data_contract::group::v0::GroupV0; + use dpp::data_contract::group::Group; use dpp::data_contract::DataContract; use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; @@ -440,7 +445,7 @@ mod tests { } #[test] - fn test_data_contract_creation_with_single_token_with_starting_balance() { + fn test_data_contract_creation_with_single_token_and_group() { let platform_version = PlatformVersion::latest(); let mut platform = TestPlatformBuilder::new() .build_with_mock_rpc() @@ -450,6 +455,10 @@ mod tests { let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + let mut data_contract = json_document_to_contract_with_ids( "tests/supporting_files/contract/basic-token/basic-token.json", None, @@ -459,21 +468,52 @@ mod tests { ) .expect("expected to get json based contract"); - let base_supply_start_amount = 10000; + let identity_id = identity.id(); + + let base_supply_start_amount = 0; { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_3.id(), 1), + (identity_2.id(), 2), + ] + .into(), + required_power: 2, + }), + ); let token_config = data_contract .tokens_mut() .expect("expected tokens") .get_mut(&0) .expect("expected first token"); + token_config.set_main_control_group(Some(1)); token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0(ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + // We have no group at position 1, we should get an error + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + })); } - let identity_id = identity.id(); - let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + let data_contract_create_transition = DataContractCreateTransition::new_from_data_contract( data_contract, 1, @@ -485,8 +525,6 @@ mod tests { ) .expect("expect to create documents batch transition"); - let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); - let data_contract_create_serialized_transition = data_contract_create_transition .serialize_to_bytes() .expect("expected documents batch serialized state transition"); @@ -522,12 +560,11 @@ mod tests { .drive .fetch_identity_token_balance(token_id, identity_id.to_buffer(), None, platform_version) .expect("expected to fetch token balance"); - assert_eq!(token_balance, Some(base_supply_start_amount)); + assert_eq!(token_balance, None); } #[test] - fn test_data_contract_creation_with_single_token_with_starting_balance_over_limit_should_cause_error( - ) { + fn test_data_contract_creation_with_single_token_with_starting_balance() { let platform_version = PlatformVersion::latest(); let mut platform = TestPlatformBuilder::new() .build_with_mock_rpc() @@ -546,7 +583,7 @@ mod tests { ) .expect("expected to get json based contract"); - let base_supply_start_amount = u64::MAX; + let base_supply_start_amount = 10000; { let token_config = data_contract @@ -592,12 +629,10 @@ mod tests { None, ) .expect("expected to process state transition"); + assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError( - ConsensusError::BasicError(BasicError::InvalidTokenBaseSupplyError(_)), - _ - )] + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] ); platform @@ -611,6 +646,1112 @@ mod tests { .drive .fetch_identity_token_balance(token_id, identity_id.to_buffer(), None, platform_version) .expect("expected to fetch token balance"); - assert_eq!(token_balance, None); + assert_eq!(token_balance, Some(base_supply_start_amount)); + } + + mod token_errors { + use super::*; + #[test] + fn test_data_contract_creation_with_single_token_with_starting_balance_over_limit_should_cause_error( + ) { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let base_supply_start_amount = u64::MAX; + + { + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_base_supply(base_supply_start_amount); + } + + let identity_id = identity.id(); + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::InvalidTokenBaseSupplyError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_data_contract_creation_with_single_token_needing_group_that_does_not_exist() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 564, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + // We have no group at position 1, we should get an error + admin_action_takers: AuthorizedActionTakers::Group(1), + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::GroupPositionDoesNotExistError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_data_contract_creation_with_single_token_setting_main_group_that_does_not_exist() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 564, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(1)); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + // We have no group at position 1, we should get an error + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::GroupPositionDoesNotExistError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + } + + mod group_errors { + use super::*; + #[test] + fn test_data_contract_creation_with_non_contiguous_groups_should_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 2, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_3.id(), 1), + (identity_2.id(), 2), + ] + .into(), + required_power: 2, + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(2)); + token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + // We have no group at position 1, we should get an error + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError( + BasicError::NonContiguousContractGroupPositionsError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_data_contract_creation_with_group_with_member_with_zero_power_should_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_3.id(), 0), //error + (identity_2.id(), 2), + ] + .into(), + required_power: 2, + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(1)); + token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::GroupMemberHasPowerOfZeroError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_data_contract_creation_with_group_with_member_with_too_big_power_should_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 50000), + (identity_3.id(), 100000), //error + (identity_2.id(), 50000), + ] + .into(), + required_power: 100000, + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(1)); + token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_data_contract_creation_with_group_with_member_with_power_over_required_should_error( + ) { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 3), + (identity_3.id(), 6), //error + (identity_2.id(), 3), + ] + .into(), + required_power: 5, + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(1)); + token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::GroupMemberHasPowerOverLimitError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_dcc_group_with_member_power_not_reaching_threshold() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_3.id(), 1), + (identity_2.id(), 1), + ] + .into(), + required_power: 5, // 1 + 1 + 1 < 5 so we should error + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(1)); + token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError(BasicError::GroupTotalPowerLessThanRequiredError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_dcc_group_with_non_unilateral_member_power_not_reaching_threshold() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 234, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 45, dash_to_credits!(0.1)); + + let mut data_contract = json_document_to_contract_with_ids( + "tests/supporting_files/contract/basic-token/basic-token.json", + None, + None, + false, //no need to validate the data contracts in tests for drive + platform_version, + ) + .expect("expected to get json based contract"); + + let identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + let groups = data_contract.groups_mut().expect("expected tokens"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_3.id(), 5), + (identity_2.id(), 1), + ] + .into(), + required_power: 5, // 1 + 1 < 5 so we should error + }), + ); + let token_config = data_contract + .tokens_mut() + .expect("expected tokens") + .get_mut(&0) + .expect("expected first token"); + token_config.set_main_control_group(Some(1)); + token_config.set_base_supply(base_supply_start_amount); + token_config.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + admin_action_takers: AuthorizedActionTakers::MainGroup, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_admin_action_takers_to_no_one_allowed: false, + self_changing_admin_action_takers_allowed: false, + }, + )); + } + + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + let data_contract_create_transition = + DataContractCreateTransition::new_from_data_contract( + data_contract, + 1, + &identity.into_partial_identity_info(), + key.id(), + &signer, + platform_version, + None, + ) + .expect("expect to create documents batch transition"); + + let data_contract_create_serialized_transition = data_contract_create_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError( + BasicError::GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id, + identity_id.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs index 9cd512b6da..d92aa92444 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs @@ -81,6 +81,11 @@ mod tests { use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use assert_matches::assert_matches; + use dpp::consensus::basic::BasicError; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::group::v0::GroupV0; + use dpp::data_contract::group::Group; use dpp::tests::fixtures::get_data_contract_fixture; use dpp::tests::json_document::json_document_to_contract; use dpp::version::PlatformVersion; @@ -665,4 +670,635 @@ mod tests { && error.additional_message() == "document type can not change creation restriction mode: changing from Owner Only to No Restrictions" )); } + + mod group_tests { + use super::*; + #[test] + fn test_data_contract_update_can_not_remove_groups() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + let platform_version = platform_state + .current_platform_version() + .expect("expected to get current platform version"); + + // Create an initial data contract with groups + let mut data_contract = + get_data_contract_fixture(None, 0, platform_version.protocol_version) + .data_contract_owned(); + + data_contract.set_owner_id(identity.id()); + + { + // Add groups to the contract + let groups = data_contract.groups_mut().expect("expected groups"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + } + + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + // Create an updated contract with one group removed + let mut updated_data_contract = data_contract.clone(); + updated_data_contract.set_version(2); + + { + // Remove a group from the updated contract + let groups = updated_data_contract.groups_mut().expect("expected groups"); + groups.remove(&1).expect("expected to remove group"); + } + + let data_contract_update_transition = + DataContractUpdateTransition::new_from_data_contract( + updated_data_contract, + &identity.into_partial_identity_info(), + key.id(), + 2, + 0, + &signer, + platform_version, + None, + ) + .expect("expect to create data contract update transition"); + + let data_contract_update_serialized_transition = data_contract_update_transition + .serialize_to_bytes() + .expect("expected serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + // Extract the error and check the message + if let [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::StateError(StateError::DataContractUpdateActionNotAllowedError( + error, + )), + _, + )] = processing_result.execution_results().as_slice() + { + assert_eq!( + error.action(), + "remove group", + "expected error message to match 'remove group'" + ); + assert_eq!( + error.data_contract_id(), + data_contract.id(), + "expected the error to reference the correct data contract ID" + ); + } else { + panic!("Expected a DataContractUpdateActionNotAllowedError"); + } + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + + #[test] + fn test_data_contract_update_can_not_alter_group() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + let platform_version = platform_state + .current_platform_version() + .expect("expected to get current platform version"); + + // Create an initial data contract with groups + let mut data_contract = + get_data_contract_fixture(None, 0, platform_version.protocol_version) + .data_contract_owned(); + + data_contract.set_owner_id(identity.id()); + + { + // Add groups to the contract + let groups = data_contract.groups_mut().expect("expected groups"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + } + + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + // Create an updated contract with one group removed + let mut updated_data_contract = data_contract.clone(); + updated_data_contract.set_version(2); + + { + // Remove a group from the updated contract + let groups = updated_data_contract.groups_mut().expect("expected groups"); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [(identity.id(), 2)].into(), + required_power: 2, + }), + ); + } + + let data_contract_update_transition = + DataContractUpdateTransition::new_from_data_contract( + updated_data_contract, + &identity.into_partial_identity_info(), + key.id(), + 2, + 0, + &signer, + platform_version, + None, + ) + .expect("expect to create data contract update transition"); + + let data_contract_update_serialized_transition = data_contract_update_transition + .serialize_to_bytes() + .expect("expected serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + // Extract the error and check the message + if let [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::StateError(StateError::DataContractUpdateActionNotAllowedError( + error, + )), + _, + )] = processing_result.execution_results().as_slice() + { + assert_eq!( + error.action(), + "change group at position 1 is not allowed", + "expected error message to match 'change group at position 1 is not allowed'" + ); + assert_eq!( + error.data_contract_id(), + data_contract.id(), + "expected the error to reference the correct data contract ID" + ); + } else { + panic!("Expected a DataContractUpdateActionNotAllowedError"); + } + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + + #[test] + fn test_data_contract_update_can_not_add_new_group_with_gap() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + let platform_version = platform_state + .current_platform_version() + .expect("expected to get current platform version"); + + // Create an initial data contract with groups + let mut data_contract = + get_data_contract_fixture(None, 0, platform_version.protocol_version) + .data_contract_owned(); + + data_contract.set_owner_id(identity.id()); + + { + // Add groups to the contract + let groups = data_contract.groups_mut().expect("expected groups"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + } + + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + // Create an updated contract with one group removed + let mut updated_data_contract = data_contract.clone(); + updated_data_contract.set_version(2); + + { + // Remove a group from the updated contract + let groups = updated_data_contract.groups_mut().expect("expected groups"); + groups.insert( + 3, + Group::V0(GroupV0 { + members: [(identity.id(), 2)].into(), + required_power: 2, + }), + ); + } + + let data_contract_update_transition = + DataContractUpdateTransition::new_from_data_contract( + updated_data_contract, + &identity.into_partial_identity_info(), + key.id(), + 2, + 0, + &signer, + platform_version, + None, + ) + .expect("expect to create data contract update transition"); + + let data_contract_update_serialized_transition = data_contract_update_transition + .serialize_to_bytes() + .expect("expected serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::BasicError( + BasicError::NonContiguousContractGroupPositionsError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + + #[test] + fn test_data_contract_update_can_add_new_group() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (identity_2, _, _) = setup_identity(&mut platform, 928, dash_to_credits!(0.1)); + + let (identity_3, _, _) = setup_identity(&mut platform, 8, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + let platform_version = platform_state + .current_platform_version() + .expect("expected to get current platform version"); + + // Create an initial data contract with groups + let mut data_contract = + get_data_contract_fixture(None, 0, platform_version.protocol_version) + .data_contract_owned(); + + data_contract.set_owner_id(identity.id()); + + { + // Add groups to the contract + let groups = data_contract.groups_mut().expect("expected groups"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_2.id(), 1), + (identity_3.id(), 1), + ] + .into(), + required_power: 3, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_2.id(), 2), + (identity_3.id(), 1), + ] + .into(), + required_power: 3, + }), + ); + } + + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + // Create an updated contract with one group removed + let mut updated_data_contract = data_contract.clone(); + updated_data_contract.set_version(2); + + { + // Remove a group from the updated contract + let groups = updated_data_contract.groups_mut().expect("expected groups"); + groups.insert( + 2, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_2.id(), 2), + (identity_3.id(), 2), + ] + .into(), + required_power: 3, + }), + ); + } + + let data_contract_update_transition = + DataContractUpdateTransition::new_from_data_contract( + updated_data_contract, + &identity.into_partial_identity_info(), + key.id(), + 2, + 0, + &signer, + platform_version, + None, + ) + .expect("expect to create data contract update transition"); + + let data_contract_update_serialized_transition = data_contract_update_transition + .serialize_to_bytes() + .expect("expected serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + } + + mod token_tests { + use super::*; + use dpp::data_contract::accessors::v1::DataContractV1Setters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + #[test] + fn test_data_contract_update_can_not_add_new_token() { + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let platform_state = platform.state.load(); + let platform_version = platform_state + .current_platform_version() + .expect("expected to get current platform version"); + + // Create an initial data contract with groups + let mut data_contract = + get_data_contract_fixture(None, 0, platform_version.protocol_version) + .data_contract_owned(); + + data_contract.set_owner_id(identity.id()); + + { + // Add groups to the contract + let groups = data_contract.groups_mut().expect("expected groups"); + groups.insert( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + groups.insert( + 1, + Group::V0(GroupV0 { + members: [(identity.id(), 1)].into(), + required_power: 1, + }), + ); + } + + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + // Create an updated contract with one group removed + let mut updated_data_contract = data_contract.clone(); + updated_data_contract.set_version(2); + + updated_data_contract.add_token( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ); + + let data_contract_update_transition = + DataContractUpdateTransition::new_from_data_contract( + updated_data_contract, + &identity.into_partial_identity_info(), + key.id(), + 2, + 0, + &signer, + platform_version, + None, + ) + .expect("expect to create data contract update transition"); + + let data_contract_update_serialized_transition = data_contract_update_transition + .serialize_to_bytes() + .expect("expected serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![data_contract_update_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + // Extract the error and check the message + if let [StateTransitionExecutionResult::PaidConsensusError( + ConsensusError::StateError(StateError::DataContractUpdateActionNotAllowedError( + error, + )), + _, + )] = processing_result.execution_results().as_slice() + { + assert_eq!( + error.action(), + "add token at position 0", + "expected error message to match 'add token at position 0'" + ); + assert_eq!( + error.data_contract_id(), + data_contract.id(), + "expected the error to reference the correct data contract ID" + ); + } else { + panic!("Expected a DataContractUpdateActionNotAllowedError"); + } + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + } } diff --git a/packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs index ef664f87f6..d9d8aa09b3 100644 --- a/packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/group_queries/group_actions/v0/mod.rs @@ -7,8 +7,8 @@ use dapi_grpc::platform::v0::get_group_actions_request::GetGroupActionsRequestV0 use dapi_grpc::platform::v0::get_group_actions_response::get_group_actions_response_v0::{ emergency_action_event, group_action_event, token_event, BurnEvent, DestroyFrozenFundsEvent, EmergencyActionEvent, FreezeEvent, GroupActionEntry, GroupActionEvent, GroupActions, MintEvent, - PersonalEncryptedNote, SharedEncryptedNote, TokenEvent as TokenEventResponse, TransferEvent, - UnfreezeEvent, + PersonalEncryptedNote, SharedEncryptedNote, TokenConfigUpdateEvent, + TokenEvent as TokenEventResponse, TransferEvent, UnfreezeEvent, }; use dapi_grpc::platform::v0::get_group_actions_response::{ get_group_actions_response_v0, GetGroupActionsResponseV0, @@ -19,6 +19,7 @@ use dpp::group::action_event; use dpp::group::group_action::GroupAction; use dpp::group::group_action_status::GroupActionStatus; use dpp::identifier::Identifier; +use dpp::serialization::PlatformSerializableWithPlatformVersion; use dpp::tokens::emergency_action::TokenEmergencyAction; use dpp::tokens::token_event::TokenEvent; use dpp::validation::ValidationResult; @@ -128,9 +129,9 @@ impl Platform { platform_version, )? .into_iter() - .map(|(action_id, group_action)| { + .filter_map(|(action_id, group_action)| { // Convert the fetched GroupAction into a GroupActionEntry - GroupActionEntry { + Some(GroupActionEntry { action_id: action_id.to_vec(), event: Some(GroupActionEvent { event_type: Some(match group_action { @@ -222,11 +223,19 @@ impl Platform { })), }) } + TokenEvent::ConfigUpdate(token_configuration_change_item, public_note) => { + group_action_event::EventType::TokenEvent(TokenEventResponse { + r#type: Some(token_event::Type::TokenConfigUpdate(TokenConfigUpdateEvent { + token_config_update_item: token_configuration_change_item.serialize_consume_to_bytes_with_platform_version(platform_version).ok()?, + public_note, + })), + }) + } }, }, }), }), - } + }) }) .collect(); GetGroupActionsResponseV0 { diff --git a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs index 4cd29a9d94..a7f8b30c99 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs @@ -576,6 +576,7 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( .as_ref() .expect("expected last commited block info") .basic_info(), + platform_version, ) .expect("expected to build historical document"); diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/basic-token/basic-token.json b/packages/rs-drive-abci/tests/supporting_files/contract/basic-token/basic-token.json index 7f103653d8..ec2a3fd928 100644 --- a/packages/rs-drive-abci/tests/supporting_files/contract/basic-token/basic-token.json +++ b/packages/rs-drive-abci/tests/supporting_files/contract/basic-token/basic-token.json @@ -8,6 +8,7 @@ "0": { "$format_version": "0", "conventions": { + "$format_version": "0", "decimals": 8 }, "baseSupply": 100000, diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index be5ae7dedb..c54c7dbc02 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/contract/get_fetch/fetch_contract/v0/mod.rs b/packages/rs-drive/src/drive/contract/get_fetch/fetch_contract/v0/mod.rs index fa3a6fa1a8..0d40cd945e 100644 --- a/packages/rs-drive/src/drive/contract/get_fetch/fetch_contract/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/get_fetch/fetch_contract/v0/mod.rs @@ -77,7 +77,7 @@ impl Drive { match value { Ok(Element::Item(stored_contract_bytes, element_flag)) => { let contract = cost_return_on_error_no_add!( - &cost, + cost, DataContract::versioned_deserialize( &stored_contract_bytes, false, @@ -88,7 +88,7 @@ impl Drive { let drive_operation = CalculatedCostOperation(cost.clone()); let fee = if let Some(epoch) = epoch { Some(cost_return_on_error_no_add!( - &cost, + cost, Drive::calculate_fee( None, Some(vec![drive_operation]), @@ -103,7 +103,7 @@ impl Drive { }; let storage_flags = cost_return_on_error_no_add!( - &cost, + cost, StorageFlags::map_some_element_flags_ref(&element_flag) .map_err(Error::StorageFlags) ); @@ -134,7 +134,7 @@ impl Drive { match value { Ok(Element::Item(stored_contract_bytes, element_flag)) => { let contract = cost_return_on_error_no_add!( - &cost, + cost, DataContract::versioned_deserialize( &stored_contract_bytes, false, @@ -145,7 +145,7 @@ impl Drive { let drive_operation = CalculatedCostOperation(cost.clone()); let fee = if let Some(epoch) = epoch { Some(cost_return_on_error_no_add!( - &cost, + cost, Drive::calculate_fee( None, Some(vec![drive_operation]), @@ -160,7 +160,7 @@ impl Drive { }; let storage_flags = cost_return_on_error_no_add!( - &cost, + cost, StorageFlags::map_some_element_flags_ref(&element_flag) .map_err(Error::StorageFlags) ); diff --git a/packages/rs-drive/src/drive/group/estimated_costs/for_add_groups/mod.rs b/packages/rs-drive/src/drive/group/estimated_costs/for_add_groups/mod.rs new file mode 100644 index 0000000000..4c11fd514c --- /dev/null +++ b/packages/rs-drive/src/drive/group/estimated_costs/for_add_groups/mod.rs @@ -0,0 +1,74 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::version::drive_versions::DriveVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerInformation; +use std::collections::{BTreeMap, HashMap}; + +impl Drive { + /// Adds estimated costs for the layer information of group updates in a contract. + /// + /// This function updates the `estimated_costs_only_with_layer_info` map with the layer information for + /// the trees involved in adding or updating a group action in the context of a contract. The trees are + /// organized hierarchically based on their role in the system, such as "Group Actions", "Withdrawal Transactions", + /// "Balances", and "Contract/Documents". This estimation is used to determine the computational costs associated + /// with updating these trees, considering whether they are sum trees or normal trees and their expected layer counts. + /// + /// The function breaks down the tree layers and their corresponding costs as follows: + /// 1. **Group Actions Tree**: A normal tree that holds information about group actions in the contract. + /// 2. **Withdrawal Transactions Tree**: A normal tree that holds withdrawal transaction data. + /// 3. **Balances Tree**: A sum tree that holds balance information, which is crucial for cost estimation. + /// 4. **Contract/Documents Tree**: A normal tree that holds contract and document-related data. + /// + /// Each tree's cost is estimated based on its depth and whether it's a sum tree or not. The function inserts the + /// estimated layer information for each relevant tree in the `estimated_costs_only_with_layer_info` map, where + /// the key represents the path to the specific tree and the value represents its estimated layer information. + /// + /// # Parameters + /// + /// - `contract_id`: The unique identifier of the contract being updated. Used to construct paths for the trees. + /// - `groups`: The groups that we will insert. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to a `HashMap` where the estimated layer information + /// will be inserted. The keys represent paths to the trees, and the values represent their estimated layer information. + /// + /// # Logic Breakdown + /// + /// - **Top Layer (Contract/Documents)**: The contract and documents tree is at the top level, with a weight of 2. + /// - **Balance Tree (Sum Tree)**: The balance tree is a sum tree with a weight of 1. + /// - **Withdrawal Transactions**: This tree is a normal tree, and it is expected to have a weight of 2. + /// - **Group Action Tree**: The group action tree is also a normal tree, with an expected weight of 2. + /// - **Additional Layer Costs**: For specific paths related to actions, signers, etc., further estimations are added with + /// appropriate layer counts and subtree size estimations. + /// + /// The function constructs the paths based on the contract ID, group contract position, and action ID (if provided). + /// It then populates the `estimated_costs_only_with_layer_info` map with the estimated costs for each relevant tree + /// involved in the group action update. + + pub(crate) fn add_estimation_costs_for_add_groups( + contract_id: [u8; 32], + groups: &BTreeMap, + estimated_costs_only_with_layer_info: &mut HashMap, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version.methods.group.cost_estimation.for_add_group { + 0 => { + Self::add_estimation_costs_for_add_groups_v0( + contract_id, + groups, + estimated_costs_only_with_layer_info, + ); + Ok(()) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_estimation_costs_for_add_group".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/estimated_costs/for_add_groups/v0/mod.rs b/packages/rs-drive/src/drive/group/estimated_costs/for_add_groups/v0/mod.rs new file mode 100644 index 0000000000..b87806d4ab --- /dev/null +++ b/packages/rs-drive/src/drive/group/estimated_costs/for_add_groups/v0/mod.rs @@ -0,0 +1,88 @@ +use crate::drive::Drive; + +use crate::drive::group::paths::{group_contract_path, group_path, group_root_path}; +use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::EstimatedLevel; +use grovedb::EstimatedLayerSizes::AllSubtrees; +use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; +use std::collections::{BTreeMap, HashMap}; + +impl Drive { + pub(super) fn add_estimation_costs_for_add_groups_v0( + contract_id: [u8; 32], + groups: &BTreeMap, + estimated_costs_only_with_layer_info: &mut HashMap, + ) { + // 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 GroupActions 88 Misc 104 Versions 120 + + // we have constructed the top layer so contract/documents tree are at the top + // since balance will be on layer 3 (level 2 on left then left) + // updating will mean we will update: + // 1 normal tree (group actions) + // 1 normal tree (withdrawal transactions) + // 1 sum tree (balances) + // 1 normal tree (contract/documents) + // hence we should give an equal weight to both + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path([]), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(3, false), + estimated_layer_sizes: AllSubtrees( + 1, + SomeSumTrees { + sum_trees_weight: 1, + big_sum_trees_weight: 0, + count_trees_weight: 0, + count_sum_trees_weight: 0, + non_sum_trees_weight: 2, + }, + None, + ), + }, + ); + + // there is one tree for the root path + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(group_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), // We estimate that on average we need to update 10 nodes + estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), + }, + ); + + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(group_contract_path(contract_id.as_slice())), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(1, false), + estimated_layer_sizes: AllSubtrees(2, NoSumTrees, None), + }, + ); + + for group_contract_position in groups.keys() { + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(group_path( + contract_id.as_slice(), + &group_contract_position.to_be_bytes(), + )), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(1, false), + estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), + }, + ); + } + } +} diff --git a/packages/rs-drive/src/drive/group/estimated_costs/mod.rs b/packages/rs-drive/src/drive/group/estimated_costs/mod.rs index ef47daecce..9537013375 100644 --- a/packages/rs-drive/src/drive/group/estimated_costs/mod.rs +++ b/packages/rs-drive/src/drive/group/estimated_costs/mod.rs @@ -1 +1,2 @@ mod for_add_group_action; +mod for_add_groups; 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 index 2535d64d7a..7838be39bd 100644 --- 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 @@ -94,6 +94,15 @@ impl Drive { transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Drive::add_estimation_costs_for_add_groups( + contract_id.to_buffer(), + groups, + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + let mut batch_operations: Vec = vec![]; let group_tree_path = group_root_path(); diff --git a/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs index 4f7a8e24c6..24da7e1129 100644 --- a/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs @@ -37,6 +37,7 @@ impl Drive { owner_id, owner_nonce, block_info, + platform_version, )?; let operations = self.add_document_for_contract_operations( diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs index f4f2e61aa8..ac5990efb1 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs @@ -1,4 +1,5 @@ mod token_burn_transition; +mod token_config_update_transition; mod token_destroy_frozen_funds_transition; mod token_emergency_action_transition; mod token_freeze_transition; diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_config_update_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_config_update_transition.rs new file mode 100644 index 0000000000..d1e20c0b7f --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_config_update_transition.rs @@ -0,0 +1,118 @@ +use std::borrow::Cow; +use dpp::block::epoch::Epoch; +use dpp::data_contract::accessors::v1::DataContractV1Setters; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::group::action_event::GroupActionEvent; +use dpp::group::group_action::GroupAction; +use dpp::group::group_action::v0::GroupActionV0; +use dpp::group::GroupStateTransitionResolvedInfo; +use dpp::identifier::Identifier; +use dpp::tokens::token_event::TokenEvent; +use platform_version::version::PlatformVersion; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::{TokenConfigUpdateTransitionAction, TokenConfigUpdateTransitionActionAccessorsV0}; +use crate::util::batch::{DataContractOperationType, DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{DataContractOperation, GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenConfigUpdateTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + _epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .token_config_update_transition + { + 0 => { + let data_contract_id = self.base().data_contract_id(); + + let identity_contract_nonce = self.base().identity_contract_nonce(); + + let mut ops = vec![IdentityOperation( + IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }, + )]; + + if let Some(GroupStateTransitionResolvedInfo { + group_contract_position, + action_id, + action_is_proposer, + signer_power, + .. + }) = self.base().store_in_group() + { + let event = TokenEvent::ConfigUpdate( + self.update_token_configuration_item().clone(), + self.public_note().cloned(), + ); + + let initialize_with_insert_action_info = if *action_is_proposer { + Some(GroupAction::V0(GroupActionV0 { + event: GroupActionEvent::TokenEvent(event), + })) + } else { + None + }; + + ops.push(GroupOperation(GroupOperationType::AddGroupAction { + contract_id: data_contract_id, + group_contract_position: *group_contract_position, + initialize_with_insert_action_info, + action_id: *action_id, + signer_identity_id: owner_id, + signer_power: *signer_power, + })); + } + + if self.base().perform_action() { + let mut contract = self.data_contract_fetch_info().contract.clone(); + let mut token_configuration = self.base().token_configuration()?.clone(); + token_configuration.apply_token_configuration_item( + self.update_token_configuration_item().clone(), + ); + contract.add_token(self.token_position(), token_configuration); + ops.push(DataContractOperation( + DataContractOperationType::ApplyContract { + contract: Cow::Owned(contract), + storage_flags: None, + }, + )); + + let token_configuration = self.base().token_configuration()?; + if token_configuration.keeps_history() { + ops.push(TokenOperation(TokenOperationType::TokenHistory { + token_id: self.token_id(), + owner_id, + nonce: identity_contract_nonce, + event: TokenEvent::ConfigUpdate( + self.update_token_configuration_item().clone(), + self.public_note_owned(), + ), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: + "TokenConfigUpdateTransitionAction::into_high_level_document_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs index adb128e016..26e9ca3788 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs @@ -7,6 +7,7 @@ use dpp::prelude::Identifier; use dpp::tokens::token_event::TokenEvent; use dpp::version::PlatformVersion; use crate::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::TokenBurnTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::TokenConfigUpdateTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::TokenEmergencyActionTransitionActionAccessorsV0; use crate::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::TokenFreezeTransitionActionAccessorsV0; @@ -51,6 +52,8 @@ impl DriveHighLevelBatchOperationConverter for TokenTransitionAction { platform_version, ) } + TokenTransitionAction::ConfigUpdateAction(token_config_update) => token_config_update + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), } } } @@ -100,6 +103,10 @@ impl TokenTransitionAction { destroy_action.public_note().cloned(), ) } + TokenTransitionAction::ConfigUpdateAction(config_update) => TokenEvent::ConfigUpdate( + config_update.update_token_configuration_item().clone(), + config_update.public_note().cloned(), + ), } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_unfreeze_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_unfreeze_transition.rs index ca853cf564..d297c2cae1 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_unfreeze_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_unfreeze_transition.rs @@ -86,7 +86,7 @@ impl DriveHighLevelBatchOperationConverter for TokenUnfreezeTransitionAction { token_id: self.token_id(), owner_id, nonce: identity_contract_nonce, - event: TokenEvent::Freeze( + event: TokenEvent::Unfreeze( self.frozen_identity_id(), self.public_note_owned(), ), diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs index af779c91c2..df9f43a199 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs @@ -13,6 +13,8 @@ pub mod token_transfer_transition_action; /// token_unfreeze_transition_action pub mod token_unfreeze_transition_action; +/// token_config_update_transition_action +pub mod token_config_update_transition_action; /// token_destroy_frozen_funds_transition_action pub mod token_destroy_frozen_funds_transition_action; /// token_emergency_action_transition_action @@ -27,9 +29,11 @@ use dpp::document::Document; use dpp::identifier::Identifier; use dpp::prelude::{DataContract, IdentityNonce}; use dpp::ProtocolError; +use platform_version::version::PlatformVersion; use crate::error::Error; use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; use crate::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::{TokenBurnTransitionAction, TokenBurnTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::{TokenConfigUpdateTransitionAction, TokenConfigUpdateTransitionActionAccessorsV0}; use crate::state_transition_action::batch::batched_transition::token_transition::token_freeze_transition_action::{TokenFreezeTransitionAction, TokenFreezeTransitionActionAccessorsV0}; use crate::state_transition_action::batch::batched_transition::token_transition::token_unfreeze_transition_action::{TokenUnfreezeTransitionAction, TokenUnfreezeTransitionActionAccessorsV0}; use crate::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::{TokenMintTransitionAction, TokenMintTransitionActionAccessorsV0}; @@ -57,6 +61,8 @@ pub enum TokenTransitionAction { EmergencyActionAction(TokenEmergencyActionTransitionAction), /// destroy frozen funds action DestroyFrozenFundsAction(TokenDestroyFrozenFundsTransitionAction), + /// update the token configuration + ConfigUpdateAction(TokenConfigUpdateTransitionAction), } impl TokenTransitionAction { @@ -70,6 +76,7 @@ impl TokenTransitionAction { TokenTransitionAction::UnfreezeAction(action) => action.base(), TokenTransitionAction::EmergencyActionAction(action) => action.base(), TokenTransitionAction::DestroyFrozenFundsAction(action) => action.base(), + TokenTransitionAction::ConfigUpdateAction(action) => action.base(), } } @@ -83,6 +90,7 @@ impl TokenTransitionAction { TokenTransitionAction::UnfreezeAction(action) => action.base_owned(), TokenTransitionAction::EmergencyActionAction(action) => action.base_owned(), TokenTransitionAction::DestroyFrozenFundsAction(action) => action.base_owned(), + TokenTransitionAction::ConfigUpdateAction(action) => action.base_owned(), } } @@ -96,6 +104,7 @@ impl TokenTransitionAction { TokenTransitionAction::UnfreezeAction(_) => "unfreeze", TokenTransitionAction::EmergencyActionAction(_) => "emergencyAction", TokenTransitionAction::DestroyFrozenFundsAction(_) => "destroyFrozenFunds", + TokenTransitionAction::ConfigUpdateAction(_) => "configUpdate", } } @@ -130,6 +139,7 @@ impl TokenTransitionAction { owner_id: Identifier, owner_nonce: IdentityNonce, block_info: &BlockInfo, + platform_version: &PlatformVersion, ) -> Result { self.associated_token_event() .build_historical_document_owned( @@ -138,6 +148,7 @@ impl TokenTransitionAction { owner_id, owner_nonce, block_info, + platform_version, ) .map_err(Error::Protocol) } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/mod.rs new file mode 100644 index 0000000000..b40ecc2310 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/mod.rs @@ -0,0 +1,66 @@ +use derive_more::From; +use dpp::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; + +/// transformer module for token freeze transition action +pub mod transformer; +mod v0; + +pub use v0::*; // re-export the v0 module items (including TokenIssuanceTransitionActionV0) + +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; + +/// Token config update transition action +#[derive(Debug, Clone, From)] +pub enum TokenConfigUpdateTransitionAction { + /// v0 + V0(TokenConfigUpdateTransitionActionV0), +} + +impl TokenConfigUpdateTransitionActionAccessorsV0 for TokenConfigUpdateTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => v0.base, + } + } + + fn update_token_configuration_item(&self) -> &TokenConfigurationChangeItem { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => &v0.update_token_configuration_item, + } + } + + fn set_update_token_configuration_item( + &mut self, + update_token_configuration_item: TokenConfigurationChangeItem, + ) { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => { + v0.update_token_configuration_item = update_token_configuration_item + } + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenConfigUpdateTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/transformer.rs new file mode 100644 index 0000000000..04ee9d1c1f --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/transformer.rs @@ -0,0 +1,117 @@ +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::{TokenConfigUpdateTransitionActionV0, TokenConfigUpdateTransitionAction}; +use dpp::state_transition::batch_transition::token_config_update_transition::TokenConfigUpdateTransition; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::BatchedTransitionAction; + +/// Implement methods to transform a `TokenConfigUpdateTransition` into a `TokenConfigUpdateTransitionAction`. +impl TokenConfigUpdateTransitionAction { + /// Transform a `TokenConfigUpdateTransition` into a `TokenConfigUpdateTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the freeze transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenConfigUpdateTransition` instance. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenConfigUpdateTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_token_config_update_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenConfigUpdateTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenConfigUpdateTransition::V0(v0) => { + TokenConfigUpdateTransitionActionV0::try_from_token_config_update_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } + + /// Transform a borrowed `TokenConfigUpdateTransition` into a `TokenConfigUpdateTransitionAction` using the provided data contract lookup. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the freeze transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenConfigUpdateTransition`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state. + /// * `drive_operations` - A mutable reference to the vector of low-level operations that need to be performed. + /// * `get_data_contract` - A closure that fetches the `DataContractFetchInfo` given a contract ID. + /// * `platform_version` - The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - A `TokenConfigUpdateTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_config_update_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenConfigUpdateTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + match value { + TokenConfigUpdateTransition::V0(v0) => { + TokenConfigUpdateTransitionActionV0::try_from_borrowed_token_config_update_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + user_fee_increase, + get_data_contract, + platform_version, + ) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/v0/mod.rs new file mode 100644 index 0000000000..9dcdcd4003 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/v0/mod.rs @@ -0,0 +1,104 @@ +mod transformer; + +use std::sync::Arc; +use dpp::data_contract::associated_token::token_configuration_item::TokenConfigurationChangeItem; +use dpp::data_contract::TokenContractPosition; +use dpp::identifier::Identifier; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token config update transition action v0 +#[derive(Debug, Clone)] +pub struct TokenConfigUpdateTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// Updated token configuration item + pub update_token_configuration_item: TokenConfigurationChangeItem, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenIssuanceTransitionActionV0` +pub trait TokenConfigUpdateTransitionActionAccessorsV0 { + /// Returns a reference to the base token transition action + fn base(&self) -> &TokenBaseTransitionAction; + + /// Consumes self and returns the base token transition action + fn base_owned(self) -> TokenBaseTransitionAction; + + /// Returns the `update_token_configuration_item` + fn update_token_configuration_item(&self) -> &TokenConfigurationChangeItem; + + /// Sets the `update_token_configuration_item` + fn set_update_token_configuration_item( + &mut self, + update_token_configuration_item: TokenConfigurationChangeItem, + ); + + /// Returns the token position in the contract + fn token_position(&self) -> TokenContractPosition { + self.base().token_position() + } + + /// Returns the token ID + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + /// Returns the data contract ID + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + /// Returns a reference to the data contract fetch info + fn data_contract_fetch_info_ref(&self) -> &Arc { + self.base().data_contract_fetch_info_ref() + } + + /// Returns the data contract fetch info + fn data_contract_fetch_info(&self) -> Arc { + self.base().data_contract_fetch_info() + } + + /// Returns the public note (optional) + fn public_note(&self) -> Option<&String>; + + /// Returns the public note (owned) + fn public_note_owned(self) -> Option; + + /// Sets the public note + fn set_public_note(&mut self, public_note: Option); +} + +impl TokenConfigUpdateTransitionActionAccessorsV0 for TokenConfigUpdateTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn update_token_configuration_item(&self) -> &TokenConfigurationChangeItem { + &self.update_token_configuration_item + } + + fn set_update_token_configuration_item( + &mut self, + update_token_configuration_item: TokenConfigurationChangeItem, + ) { + self.update_token_configuration_item = update_token_configuration_item; + } + + fn public_note(&self) -> Option<&String> { + self.public_note.as_ref() + } + + fn public_note_owned(self) -> Option { + self.public_note + } + + fn set_public_note(&mut self, public_note: Option) { + self.public_note = public_note; + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..b23f3d2ff7 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_config_update_transition_action/v0/transformer.rs @@ -0,0 +1,233 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_config_update_transition::v0::TokenConfigUpdateTransitionV0; +use dpp::ProtocolError; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_config_update_transition_action::v0::TokenConfigUpdateTransitionActionV0; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use platform_version::version::PlatformVersion; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenConfigUpdateTransitionActionV0 { + /// Converts a `TokenConfigUpdateTransitionV0` into a `TokenConfigUpdateTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token config update transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for config update. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the config update transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `transaction` - A transaction context that includes the necessary state and other details for the transition. + /// * `value` - The `TokenConfigUpdateTransitionV0` struct containing the transition data, including token amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to determine if costs should be approximated without considering + /// the full state for the operation. Useful for optimizing the transaction cost calculations. + /// * `block_info` - Information about the current block to calculate fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version, ensuring the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result, Error>` - Returns the constructed `TokenConfigUpdateTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + pub fn try_from_token_config_update_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenConfigUpdateTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + let TokenConfigUpdateTransitionV0 { + base, + + update_token_configuration_item, + public_note, + } = value; + + let mut drive_operations = vec![]; + + let base_action_validation_result = + TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + &base, + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )?; + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let base_action = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = BumpIdentityDataContractNonceAction::from_token_base_transition( + base, + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action.into(), + base_action_validation_result.errors, + ), + fee_result, + )); + } + }; + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::ConfigUpdateAction( + TokenConfigUpdateTransitionActionV0 { + base: base_action, + update_token_configuration_item, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Converts a borrowed `TokenConfigUpdateTransitionV0` into a `TokenConfigUpdateTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token config update transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant config update logic. It does not require `drive_operations` + /// to be passed as a parameter, but it manages them internally. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance that handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the config update transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenConfigUpdateTransitionV0` struct containing the transition data, including token + /// amount and recipient. + /// * `approximate_without_state_for_costs` - A flag to indicate whether costs should be approximated without full + /// state consideration. Useful for optimizing transaction cost calculations in scenarios where full state is not needed. + /// * `transaction` - The transaction context, which includes the necessary state and other details for the transition. + /// * `block_info` - Information about the current block (e.g., epoch) to help calculate transaction fees. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns a `DataContractFetchInfo` + /// containing the data contract details, including token configurations. + /// * `platform_version` - A reference to the platform version to ensure the transition respects version-specific logic. + /// + //// # Returns + /// + /// * `Result<(ConsensusValidationResult, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenConfigUpdateTransitionActionV0` and a `FeeResult` if successful. If an error occurs (e.g., missing data or + /// invalid state transition), it returns an `Error`. + /// + pub fn try_from_borrowed_token_config_update_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenConfigUpdateTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + user_fee_increase: UserFeeIncrease, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result< + ( + ConsensusValidationResult, + FeeResult, + ), + Error, + > { + let TokenConfigUpdateTransitionV0 { + base, + update_token_configuration_item, + public_note, + } = value; + + let mut drive_operations = vec![]; + + let base_action_validation_result = + TokenBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + base, + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )?; + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let base_action = match base_action_validation_result.is_valid() { + true => base_action_validation_result.into_data()?, + false => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition( + base, + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action.into(), + base_action_validation_result.errors, + ), + fee_result, + )); + } + }; + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::ConfigUpdateAction( + TokenConfigUpdateTransitionActionV0 { + base: base_action, + update_token_configuration_item: update_token_configuration_item.clone(), + public_note: public_note.clone(), + } + .into(), + )) + .into(), + fee_result, + )) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs index 69689509bc..1d4e07a908 100644 --- a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs @@ -17,6 +17,7 @@ impl TokenTransitionActionTypeGetter for TokenTransitionAction { TokenTransitionAction::DestroyFrozenFundsAction(_) => { TokenTransitionActionType::DestroyFrozenFunds } + TokenTransitionAction::ConfigUpdateAction(_) => TokenTransitionActionType::ConfigUpdate, } } } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/token.rs b/packages/rs-drive/src/util/batch/drive_op_batch/token.rs index 51b976c4dc..ad08114540 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/token.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/token.rs @@ -116,10 +116,6 @@ impl DriveLowLevelOperationConverter for TokenOperationType { mint_amount, allow_first_mint, } => { - println!( - "minting in {} token to id {} ({})", - token_id, identity_balance_holder_id, mint_amount - ); let token_id_bytes: [u8; 32] = token_id.to_buffer(); let identity_id_bytes: [u8; 32] = identity_balance_holder_id.to_buffer(); let batch_operations = drive.token_mint_operations( diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index 640961d656..507ebc81a5 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -4,6 +4,7 @@ use dpp::block::block_info::BlockInfo; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::accessors::v1::DataContractV1Getters; use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::data_contract::config::v0::DataContractConfigGettersV0; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::serialized_version::DataContractInSerializationFormat; use dpp::document::{Document, DocumentV0Getters}; @@ -33,6 +34,7 @@ use dpp::state_transition::batch_transition::batched_transition::document_transi use dpp::state_transition::batch_transition::batched_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; use dpp::state_transition::batch_transition::batched_transition::token_transition::{TokenTransition, TokenTransitionV0Methods}; use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use dpp::state_transition::batch_transition::token_config_update_transition::v0::v0_methods::TokenConfigUpdateTransitionV0Methods; use dpp::state_transition::batch_transition::token_destroy_frozen_funds_transition::v0::v0_methods::TokenDestroyFrozenFundsTransitionV0Methods; use dpp::state_transition::batch_transition::token_emergency_action_transition::v0::v0_methods::TokenEmergencyActionTransitionV0Methods; use dpp::state_transition::batch_transition::token_freeze_transition::v0::v0_methods::TokenFreezeTransitionV0Methods; @@ -335,6 +337,7 @@ impl Drive { identity_contract_nonce, &BlockInfo::default(), token_config, + platform_version, )?; let (root_hash, document) = query.verify_proof( false, @@ -500,6 +503,39 @@ impl Drive { } Ok((root_hash, VerifiedTokenStatus(token_status))) } + TokenTransition::ConfigUpdate(update) => { + let (root_hash, Some(updated_contract)) = + Drive::verify_contract( + proof, + Some(contract.config().keeps_history()), + false, + false, + contract.id().into_buffer(), + platform_version, + )? + else { + return Err(Error::Proof(ProofError::IncorrectProof( + "proof did not contain token status expected to exist because of state transition (token emergency action)".to_string()))); + }; + let mut expected_config = token_config.clone(); + expected_config.apply_token_configuration_item( + update.update_token_configuration_item().clone(), + ); + let new_token_config = updated_contract.expected_token_configuration( + token_transition.base().token_contract_position(), + ).map_err(|_| { + Error::Proof(ProofError::CorruptedProof("returned proof does not have a token configuration, which should not be possible".to_string())) + })?; + + if new_token_config != &expected_config { + return Err(Error::Proof(ProofError::IncorrectProof( + format!( + "expected token configuration does not match the token configuration from the proof: expected {}, found {}", + expected_config, new_token_config + )))); + } + Ok((root_hash, VerifiedDataContract(updated_contract))) + } } } } diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index f7b1c45da6..4f35482493 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "1.0.63" } bincode = { version = "2.0.0-rc.3" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "44c2244bbccd3e6e684729e8cf620644f7ebbf70" } once_cell = "1.19.0" [features] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/mod.rs index 6f74987f92..237f7c75c0 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/mod.rs @@ -23,6 +23,7 @@ pub struct DataContractMethodVersions { pub validate_document: FeatureVersion, pub validate_update: FeatureVersion, pub schema: FeatureVersion, + pub validate_groups: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v1.rs index 5483e66c95..467d367033 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v1.rs @@ -19,6 +19,7 @@ pub const CONTRACT_VERSIONS_V1: DPPContractVersions = DPPContractVersions { validate_document: 0, validate_update: 0, schema: 0, + validate_groups: 0, }, document_type_versions: DocumentTypeVersions { index_versions: DocumentTypeIndexVersions { diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v2.rs index 5dd797e201..854a3dc331 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v2.rs @@ -19,6 +19,7 @@ pub const CONTRACT_VERSIONS_V2: DPPContractVersions = DPPContractVersions { validate_document: 0, validate_update: 0, schema: 0, + validate_groups: 0, }, document_type_versions: DocumentTypeVersions { index_versions: DocumentTypeIndexVersions { diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/mod.rs index c794e0ae1b..b96453f623 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/mod.rs @@ -20,6 +20,7 @@ pub struct DataContractValidationVersions { pub validate_index_naming_duplicates: FeatureVersion, pub validate_not_defined_properties: FeatureVersion, pub validate_property_definition: FeatureVersion, + pub validate_token_config_groups_exist: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v1.rs index 38dd978bf0..6b92b0d549 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v1.rs @@ -18,6 +18,7 @@ pub const DPP_VALIDATION_VERSIONS_V1: DPPValidationVersions = DPPValidationVersi validate_index_naming_duplicates: 0, validate_not_defined_properties: 0, validate_property_definition: 0, + validate_token_config_groups_exist: 0, }, document_type: DocumentTypeValidationVersions { validate_update: 0, diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v2.rs index dcc7727e15..05f6c86706 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_validation_versions/v2.rs @@ -18,6 +18,7 @@ pub const DPP_VALIDATION_VERSIONS_V2: DPPValidationVersions = DPPValidationVersi validate_index_naming_duplicates: 0, validate_not_defined_properties: 0, validate_property_definition: 0, + validate_token_config_groups_exist: 0, }, document_type: DocumentTypeValidationVersions { validate_update: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index 0fe429b592..587366149e 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs @@ -105,6 +105,7 @@ pub struct DriveAbciDocumentsStateTransitionValidationVersions { pub token_burn_transition_state_validation: FeatureVersion, pub token_transfer_transition_state_validation: FeatureVersion, pub token_base_transition_structure_validation: FeatureVersion, + pub token_base_transition_state_validation: FeatureVersion, pub token_freeze_transition_structure_validation: FeatureVersion, pub token_unfreeze_transition_structure_validation: FeatureVersion, pub token_freeze_transition_state_validation: FeatureVersion, @@ -113,6 +114,9 @@ pub struct DriveAbciDocumentsStateTransitionValidationVersions { pub token_destroy_frozen_funds_transition_state_validation: FeatureVersion, pub token_emergency_action_transition_structure_validation: FeatureVersion, pub token_emergency_action_transition_state_validation: FeatureVersion, + pub token_config_update_transition_structure_validation: FeatureVersion, + pub token_config_update_transition_state_validation: FeatureVersion, + pub token_base_transition_group_action_validation: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 11dc69053f..7b397d9642 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -136,6 +136,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = token_burn_transition_state_validation: 0, token_transfer_transition_state_validation: 0, token_base_transition_structure_validation: 0, + token_base_transition_state_validation: 0, token_freeze_transition_structure_validation: 0, token_unfreeze_transition_structure_validation: 0, token_freeze_transition_state_validation: 0, @@ -144,6 +145,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = token_destroy_frozen_funds_transition_state_validation: 0, token_emergency_action_transition_structure_validation: 0, token_emergency_action_transition_state_validation: 0, + token_config_update_transition_structure_validation: 0, + token_config_update_transition_state_validation: 0, + token_base_transition_group_action_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index 2a08f59b38..3df6d962f5 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -136,6 +136,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = token_burn_transition_state_validation: 0, token_transfer_transition_state_validation: 0, token_base_transition_structure_validation: 0, + token_base_transition_state_validation: 0, token_freeze_transition_structure_validation: 0, token_unfreeze_transition_structure_validation: 0, token_freeze_transition_state_validation: 0, @@ -144,6 +145,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = token_destroy_frozen_funds_transition_state_validation: 0, token_emergency_action_transition_structure_validation: 0, token_emergency_action_transition_state_validation: 0, + token_config_update_transition_structure_validation: 0, + token_config_update_transition_state_validation: 0, + token_base_transition_group_action_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index d706f0d838..e3aadceb22 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -136,6 +136,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = token_burn_transition_state_validation: 0, token_transfer_transition_state_validation: 0, token_base_transition_structure_validation: 0, + token_base_transition_state_validation: 0, token_freeze_transition_structure_validation: 0, token_unfreeze_transition_structure_validation: 0, token_freeze_transition_state_validation: 0, @@ -144,6 +145,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = token_destroy_frozen_funds_transition_state_validation: 0, token_emergency_action_transition_structure_validation: 0, token_emergency_action_transition_state_validation: 0, + token_config_update_transition_structure_validation: 0, + token_config_update_transition_state_validation: 0, + token_base_transition_group_action_validation: 0, }, }, has_nonce_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs index 0faa2b63f6..aa0ded1027 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs @@ -139,6 +139,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = token_burn_transition_state_validation: 0, token_transfer_transition_state_validation: 0, token_base_transition_structure_validation: 0, + token_base_transition_state_validation: 0, token_freeze_transition_structure_validation: 0, token_unfreeze_transition_structure_validation: 0, token_freeze_transition_state_validation: 0, @@ -147,6 +148,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = token_destroy_frozen_funds_transition_state_validation: 0, token_emergency_action_transition_structure_validation: 0, token_emergency_action_transition_state_validation: 0, + token_config_update_transition_structure_validation: 0, + token_config_update_transition_state_validation: 0, + token_base_transition_group_action_validation: 0, }, }, has_nonce_validation: 1, // <---- changed this diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index b5d4d8c3aa..0c3bcfea28 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -140,6 +140,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = token_burn_transition_state_validation: 0, token_transfer_transition_state_validation: 0, token_base_transition_structure_validation: 0, + token_base_transition_state_validation: 0, token_freeze_transition_structure_validation: 0, token_unfreeze_transition_structure_validation: 0, token_freeze_transition_state_validation: 0, @@ -148,6 +149,9 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = token_destroy_frozen_funds_transition_state_validation: 0, token_emergency_action_transition_structure_validation: 0, token_emergency_action_transition_state_validation: 0, + token_config_update_transition_structure_validation: 0, + token_config_update_transition_state_validation: 0, + token_base_transition_group_action_validation: 0, }, }, has_nonce_validation: 1, 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 index 5d4e390d7e..c2a337ebe4 100644 --- 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 @@ -39,4 +39,5 @@ pub struct DriveGroupInsertMethodVersions { #[derive(Clone, Debug, Default)] pub struct DriveGroupCostEstimationMethodVersions { pub for_add_group_action: FeatureVersion, + pub for_add_group: FeatureVersion, } 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 index 259a9029f6..e6ee9e129f 100644 --- 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 @@ -26,5 +26,6 @@ pub const DRIVE_GROUP_METHOD_VERSIONS_V1: DriveGroupMethodVersions = DriveGroupM }, cost_estimation: DriveGroupCostEstimationMethodVersions { for_add_group_action: 0, + for_add_group: 0, }, }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs index 58fa89dddd..23c81d18ce 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs @@ -37,6 +37,7 @@ pub struct DriveStateTransitionActionConvertToHighLevelOperationsMethodVersions pub token_unfreeze_transition: FeatureVersion, pub token_emergency_action_transition: FeatureVersion, pub token_destroy_frozen_funds_transition: FeatureVersion, + pub token_config_update_transition: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs index 772b880711..5db70c5c19 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs @@ -39,5 +39,6 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1: DriveStateTransitionMethodV token_unfreeze_transition: 0, token_emergency_action_transition: 0, token_destroy_frozen_funds_transition: 0, + token_config_update_transition: 0, }, }; 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 9a4de6099f..81a8d0dbba 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -386,6 +386,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { withdrawal_transactions_per_block_limit: 4, retry_signing_expired_withdrawal_documents_per_block_limit: 1, max_withdrawal_amount: 50_000_000_000_000, + max_contract_group_size: 256, }, consensus: ConsensusVersions { tenderdash_consensus_version: 0, diff --git a/packages/rs-platform-version/src/version/system_limits/mod.rs b/packages/rs-platform-version/src/version/system_limits/mod.rs index 0dd2c5b922..4460d29d13 100644 --- a/packages/rs-platform-version/src/version/system_limits/mod.rs +++ b/packages/rs-platform-version/src/version/system_limits/mod.rs @@ -9,4 +9,5 @@ pub struct SystemLimits { pub withdrawal_transactions_per_block_limit: u16, pub retry_signing_expired_withdrawal_documents_per_block_limit: u16, pub max_withdrawal_amount: u64, + pub max_contract_group_size: u32, } diff --git a/packages/rs-platform-version/src/version/system_limits/v1.rs b/packages/rs-platform-version/src/version/system_limits/v1.rs index 6dacce0b35..b62f7bfcd0 100644 --- a/packages/rs-platform-version/src/version/system_limits/v1.rs +++ b/packages/rs-platform-version/src/version/system_limits/v1.rs @@ -8,4 +8,5 @@ pub const SYSTEM_LIMITS_V1: SystemLimits = SystemLimits { withdrawal_transactions_per_block_limit: 4, retry_signing_expired_withdrawal_documents_per_block_limit: 1, max_withdrawal_amount: 50_000_000_000_000, //500 Dash + max_contract_group_size: 256, }; diff --git a/packages/token-history-contract/schema/v1/token-history-contract-documents.json b/packages/token-history-contract/schema/v1/token-history-contract-documents.json index e6d96fd8f7..f8d1af53b0 100644 --- a/packages/token-history-contract/schema/v1/token-history-contract-documents.json +++ b/packages/token-history-contract/schema/v1/token-history-contract-documents.json @@ -576,5 +576,76 @@ "$createdAtBlockHeight" ], "additionalProperties": false + }, + "configUpdate": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "changeItemType": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byChangeItemType", + "properties": [ + { + "tokenId": "asc" + }, + { + "changeItemType": "asc" + }, + { + "$createdAt": "asc" + } + ] + } + ], + "properties": { + "tokenId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The token ID", + "position": 0, + "contentMediaType": "application/x.dash.dpp.identifier" + }, + "changeItemType": { + "type": "integer", + "minimum": 0, + "description": "The action we are performing", + "position": 1 + }, + "changeItem": { + "type": "array", + "byteArray": true, + "minItems": 1, + "description": "The change item in serialized form", + "position": 2 + } + }, + "required": [ + "tokenId", + "changeItemType", + "changeItem", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false } } diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index c3105e3187..36d42b5936 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -61,12 +61,13 @@ use dpp::consensus::state::data_trigger::DataTriggerError::{ DataTriggerConditionError, DataTriggerExecutionError, DataTriggerInvalidResultError, }; use wasm_bindgen::{JsError, JsValue}; -use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidTokenBaseSupplyError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; +use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, GroupTotalPowerLessThanRequiredError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidTokenBaseSupplyError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedError, DocumentCreationNotAllowedError, DocumentFieldMaxSizeExceededError, MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError}; use dpp::consensus::basic::group::GroupActionNotAllowedOnTransitionError; use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError}; use dpp::consensus::basic::overflow_error::OverflowError; use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidGroupPositionError, InvalidTokenIdError, InvalidTokenPositionError, TokenTransferToOurselfError}; +use dpp::consensus::state::data_contract::data_contract_update_action_not_allowed_error::DataContractUpdateActionNotAllowedError; use dpp::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; use dpp::consensus::state::document::document_contest_currently_locked_error::DocumentContestCurrentlyLockedError; use dpp::consensus::state::document::document_contest_document_with_same_id_already_present_error::DocumentContestDocumentWithSameIdAlreadyPresentError; @@ -340,6 +341,9 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::IdentityTokenAccountNotFrozenError(e) => { generic_consensus_error!(IdentityTokenAccountNotFrozenError, e).into() } + StateError::DataContractUpdateActionNotAllowedError(e) => { + generic_consensus_error!(DataContractUpdateActionNotAllowedError, e).into() + } } } @@ -646,6 +650,28 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::GroupActionNotAllowedOnTransitionError(e) => { generic_consensus_error!(GroupActionNotAllowedOnTransitionError, e).into() } + BasicError::GroupPositionDoesNotExistError(e) => { + generic_consensus_error!(GroupPositionDoesNotExistError, e).into() + } + BasicError::GroupExceedsMaxMembersError(e) => { + generic_consensus_error!(GroupExceedsMaxMembersError, e).into() + } + BasicError::GroupMemberHasPowerOfZeroError(e) => { + generic_consensus_error!(GroupMemberHasPowerOfZeroError, e).into() + } + BasicError::GroupMemberHasPowerOverLimitError(e) => { + generic_consensus_error!(GroupMemberHasPowerOverLimitError, e).into() + } + BasicError::GroupTotalPowerLessThanRequiredError(e) => { + generic_consensus_error!(GroupTotalPowerLessThanRequiredError, e).into() + } + BasicError::GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError(e) => { + generic_consensus_error!( + GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, + e + ) + .into() + } } }