Skip to content

Commit be85e0d

Browse files
fix(dpp): handle MainGroupIsNotDefinedError in token configuration (#2594)
1 parent ee8c09d commit be85e0d

File tree

10 files changed

+172
-8
lines changed

10 files changed

+172
-8
lines changed

packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl TokenConfigurationV0Getters for TokenConfiguration {
150150
}
151151

152152
/// Returns all group positions used in the token configuration
153-
fn all_used_group_positions(&self) -> BTreeSet<GroupContractPosition> {
153+
fn all_used_group_positions(&self) -> (BTreeSet<GroupContractPosition>, bool) {
154154
match self {
155155
TokenConfiguration::V0(v0) => v0.all_used_group_positions(),
156156
}

packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ pub trait TokenConfigurationV0Getters {
6969
fn main_control_group_can_be_modified(&self) -> &AuthorizedActionTakers;
7070

7171
/// Returns all group positions used in the token configuration
72-
fn all_used_group_positions(&self) -> BTreeSet<GroupContractPosition>;
72+
fn all_used_group_positions(&self) -> (BTreeSet<GroupContractPosition>, bool);
7373

7474
/// Returns all the change contract rules, including those from the distribution rules
7575
fn all_change_control_rules(&self) -> Vec<(&str, &ChangeControlRules)>;

packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_groups_exist/v0/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::consensus::basic::data_contract::GroupPositionDoesNotExistError;
1+
use crate::consensus::basic::data_contract::{
2+
GroupPositionDoesNotExistError, MainGroupIsNotDefinedError,
3+
};
24
use crate::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters;
35
use crate::data_contract::associated_token::token_configuration::TokenConfiguration;
46
use crate::data_contract::group::Group;
@@ -16,7 +18,7 @@ impl TokenConfiguration {
1618
let validation_result = SimpleConsensusValidationResult::new();
1719

1820
// Collect all group positions used in the token configuration
19-
let group_positions = self.all_used_group_positions();
21+
let (group_positions, uses_main_group) = self.all_used_group_positions();
2022

2123
// Check that all referenced group positions exist in the provided groups map
2224
for group_position in group_positions {
@@ -27,6 +29,12 @@ impl TokenConfiguration {
2729
}
2830
}
2931

32+
if uses_main_group && self.main_control_group().is_none() {
33+
return SimpleConsensusValidationResult::new_with_error(
34+
MainGroupIsNotDefinedError::new().into(),
35+
);
36+
}
37+
3038
// If a main group is defined in the token configuration, verify its existence
3139
if let Some(main_group_position) = self.main_control_group() {
3240
if !groups.contains_key(&main_group_position) {

packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,9 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 {
114114
}
115115

116116
/// Returns all group positions used in the token configuration
117-
fn all_used_group_positions(&self) -> BTreeSet<GroupContractPosition> {
117+
fn all_used_group_positions(&self) -> (BTreeSet<GroupContractPosition>, bool) {
118118
let mut group_positions = BTreeSet::new();
119+
let mut uses_main_group = false;
119120

120121
// Add the main control group if it exists
121122
if let Some(main_group_position) = self.main_control_group {
@@ -126,6 +127,8 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 {
126127
let mut add_from_authorized_action_takers = |authorized_takers: &AuthorizedActionTakers| {
127128
if let AuthorizedActionTakers::Group(group_position) = authorized_takers {
128129
group_positions.insert(*group_position);
130+
} else if let AuthorizedActionTakers::MainGroup = authorized_takers {
131+
uses_main_group = true;
129132
}
130133
};
131134

@@ -157,7 +160,7 @@ impl TokenConfigurationV0Getters for TokenConfigurationV0 {
157160
// Add positions from the `main_control_group_can_be_modified` field
158161
add_from_authorized_action_takers(&self.main_control_group_can_be_modified);
159162

160-
group_positions
163+
(group_positions, uses_main_group)
161164
}
162165

163166
fn all_change_control_rules(&self) -> Vec<(&str, &ChangeControlRules)> {

packages/rs-dpp/src/errors/consensus/basic/basic_error.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::consensus::basic::data_contract::{
2121
InvalidTokenDistributionFunctionIncoherenceError,
2222
InvalidTokenDistributionFunctionInvalidParameterError,
2323
InvalidTokenDistributionFunctionInvalidParameterTupleError, InvalidTokenLanguageCodeError,
24-
InvalidTokenNameCharacterError, InvalidTokenNameLengthError,
24+
InvalidTokenNameCharacterError, InvalidTokenNameLengthError, MainGroupIsNotDefinedError,
2525
NewTokensDestinationIdentityOptionRequiredError, NonContiguousContractGroupPositionsError,
2626
NonContiguousContractTokenPositionsError, SystemPropertyIndexAlreadyPresentError,
2727
UndefinedIndexPropertyError, UniqueIndicesLimitReachedError,
@@ -554,6 +554,9 @@ pub enum BasicError {
554554

555555
#[error(transparent)]
556556
InvalidTokenLanguageCodeError(InvalidTokenLanguageCodeError),
557+
558+
#[error(transparent)]
559+
MainGroupIsNotDefinedError(MainGroupIsNotDefinedError),
557560
}
558561

559562
impl From<BasicError> for ConsensusError {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use crate::consensus::basic::BasicError;
2+
use crate::consensus::ConsensusError;
3+
use crate::ProtocolError;
4+
use bincode::{Decode, Encode};
5+
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
6+
use thiserror::Error;
7+
8+
#[derive(
9+
Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize,
10+
)]
11+
#[error("Main group is not defined.")]
12+
#[platform_serialize(unversioned)]
13+
pub struct MainGroupIsNotDefinedError;
14+
15+
impl Default for MainGroupIsNotDefinedError {
16+
fn default() -> Self {
17+
Self::new()
18+
}
19+
}
20+
21+
impl MainGroupIsNotDefinedError {
22+
pub fn new() -> Self {
23+
Self {}
24+
}
25+
}
26+
27+
impl From<MainGroupIsNotDefinedError> for ConsensusError {
28+
fn from(err: MainGroupIsNotDefinedError) -> Self {
29+
Self::BasicError(BasicError::MainGroupIsNotDefinedError(err))
30+
}
31+
}

packages/rs-dpp/src/errors/consensus/basic/data_contract/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ mod invalid_token_language_code_error;
3939
mod invalid_token_name_character_error;
4040
mod invalid_token_name_length_error;
4141
mod keywords_over_limit;
42+
mod main_group_is_not_defined;
4243
mod new_tokens_destination_identity_option_required_error;
4344
mod non_contiguous_contract_group_positions_error;
4445
mod non_contiguous_contract_token_positions_error;
@@ -100,6 +101,7 @@ pub use invalid_token_language_code_error::*;
100101
pub use invalid_token_name_character_error::*;
101102
pub use invalid_token_name_length_error::*;
102103
pub use keywords_over_limit::*;
104+
pub use main_group_is_not_defined::*;
103105
pub use new_tokens_destination_identity_option_required_error::*;
104106
pub use non_contiguous_contract_group_positions_error::*;
105107
pub use non_contiguous_contract_token_positions_error::*;

packages/rs-dpp/src/errors/consensus/codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ impl ErrorWithCode for BasicError {
116116
Self::InvalidKeywordCharacterError(_) => 10269,
117117
Self::InvalidKeywordLengthError(_) => 10270,
118118
Self::DecimalsOverLimitError(_) => 10271,
119+
Self::MainGroupIsNotDefinedError(_) => 10272,
119120

120121
// Group Errors: 10350-10399
121122
Self::GroupPositionDoesNotExistError(_) => 10350,

packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,119 @@ mod tests {
18611861
assert_eq!(token_balance, None);
18621862
}
18631863

1864+
#[test]
1865+
fn test_data_contract_creation_with_single_token_setting_authorization_to_non_defined_main_group(
1866+
) {
1867+
let platform_version = PlatformVersion::latest();
1868+
let mut platform = TestPlatformBuilder::new()
1869+
.build_with_mock_rpc()
1870+
.set_genesis_state();
1871+
1872+
let platform_state = platform.state.load();
1873+
1874+
let (identity, signer, key) =
1875+
setup_identity(&mut platform, 958, dash_to_credits!(1.0));
1876+
1877+
let (identity_2, _, _) = setup_identity(&mut platform, 564, dash_to_credits!(0.1));
1878+
1879+
let mut data_contract = json_document_to_contract_with_ids(
1880+
"tests/supporting_files/contract/basic-token/basic-token.json",
1881+
None,
1882+
None,
1883+
false, //no need to validate the data contracts in tests for drive
1884+
platform_version,
1885+
)
1886+
.expect("expected to get json based contract");
1887+
1888+
let identity_id = identity.id();
1889+
1890+
{
1891+
let groups = data_contract.groups_mut().expect("expected tokens");
1892+
groups.insert(
1893+
0,
1894+
Group::V0(GroupV0 {
1895+
members: [(identity.id(), 1), (identity_2.id(), 1)].into(),
1896+
required_power: 2,
1897+
}),
1898+
);
1899+
let token_config = data_contract
1900+
.tokens_mut()
1901+
.expect("expected tokens")
1902+
.get_mut(&0)
1903+
.expect("expected first token");
1904+
token_config.set_manual_minting_rules(ChangeControlRules::V0(
1905+
ChangeControlRulesV0 {
1906+
authorized_to_make_change: AuthorizedActionTakers::MainGroup,
1907+
// We have no group at position 1, we should get an error
1908+
admin_action_takers: AuthorizedActionTakers::MainGroup,
1909+
changing_authorized_action_takers_to_no_one_allowed: false,
1910+
changing_admin_action_takers_to_no_one_allowed: false,
1911+
self_changing_admin_action_takers_allowed: false,
1912+
},
1913+
));
1914+
}
1915+
1916+
let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
1917+
1918+
let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
1919+
1920+
let data_contract_create_transition =
1921+
DataContractCreateTransition::new_from_data_contract(
1922+
data_contract,
1923+
1,
1924+
&identity.into_partial_identity_info(),
1925+
key.id(),
1926+
&signer,
1927+
platform_version,
1928+
None,
1929+
)
1930+
.expect("expect to create documents batch transition");
1931+
1932+
let data_contract_create_serialized_transition = data_contract_create_transition
1933+
.serialize_to_bytes()
1934+
.expect("expected documents batch serialized state transition");
1935+
1936+
let transaction = platform.drive.grove.start_transaction();
1937+
1938+
let processing_result = platform
1939+
.platform
1940+
.process_raw_state_transitions(
1941+
&[data_contract_create_serialized_transition.clone()],
1942+
&platform_state,
1943+
&BlockInfo::default(),
1944+
&transaction,
1945+
platform_version,
1946+
false,
1947+
None,
1948+
)
1949+
.expect("expected to process state transition");
1950+
1951+
assert_matches!(
1952+
processing_result.execution_results().as_slice(),
1953+
[StateTransitionExecutionResult::UnpaidConsensusError(
1954+
ConsensusError::BasicError(BasicError::MainGroupIsNotDefinedError(_)),
1955+
)]
1956+
);
1957+
1958+
platform
1959+
.drive
1960+
.grove
1961+
.commit_transaction(transaction)
1962+
.unwrap()
1963+
.expect("expected to commit transaction");
1964+
1965+
let token_balance = platform
1966+
.drive
1967+
.fetch_identity_token_balance(
1968+
token_id,
1969+
identity_id.to_buffer(),
1970+
None,
1971+
platform_version,
1972+
)
1973+
.expect("expected to fetch token balance");
1974+
assert_eq!(token_balance, None);
1975+
}
1976+
18641977
#[test]
18651978
fn test_data_contract_creation_with_single_token_setting_identifier_that_does_not_exist(
18661979
) {

packages/wasm-dpp/src/errors/consensus/consensus_error.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use dpp::consensus::state::data_trigger::DataTriggerError::{
6161
DataTriggerConditionError, DataTriggerExecutionError, DataTriggerInvalidResultError,
6262
};
6363
use wasm_bindgen::{JsError, JsValue};
64-
use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, DecimalsOverLimitError, DuplicateKeywordsError, GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, GroupTotalPowerLessThanRequiredError, InvalidDescriptionLengthError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidKeywordCharacterError, InvalidKeywordLengthError, InvalidTokenBaseSupplyError, InvalidTokenDistributionFunctionDivideByZeroError, InvalidTokenDistributionFunctionIncoherenceError, InvalidTokenDistributionFunctionInvalidParameterError, InvalidTokenDistributionFunctionInvalidParameterTupleError, InvalidTokenLanguageCodeError, InvalidTokenNameCharacterError, InvalidTokenNameLengthError, NewTokensDestinationIdentityOptionRequiredError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, TokenPaymentByBurningOnlyAllowedOnInternalTokenError, TooManyKeywordsError, UnknownDocumentActionTokenEffectError, UnknownDocumentCreationRestrictionModeError, UnknownGasFeesPaidByError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError};
64+
use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, DecimalsOverLimitError, DuplicateKeywordsError, GroupExceedsMaxMembersError, GroupMemberHasPowerOfZeroError, GroupMemberHasPowerOverLimitError, GroupNonUnilateralMemberPowerHasLessThanRequiredPowerError, GroupPositionDoesNotExistError, GroupTotalPowerLessThanRequiredError, InvalidDescriptionLengthError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidKeywordCharacterError, InvalidKeywordLengthError, InvalidTokenBaseSupplyError, InvalidTokenDistributionFunctionDivideByZeroError, InvalidTokenDistributionFunctionIncoherenceError, InvalidTokenDistributionFunctionInvalidParameterError, InvalidTokenDistributionFunctionInvalidParameterTupleError, InvalidTokenLanguageCodeError, InvalidTokenNameCharacterError, InvalidTokenNameLengthError, MainGroupIsNotDefinedError, NewTokensDestinationIdentityOptionRequiredError, NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, TokenPaymentByBurningOnlyAllowedOnInternalTokenError, TooManyKeywordsError, UnknownDocumentActionTokenEffectError, UnknownDocumentCreationRestrictionModeError, UnknownGasFeesPaidByError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError};
6565
use dpp::consensus::basic::document::{ContestedDocumentsTemporarilyNotAllowedError, DocumentCreationNotAllowedError, DocumentFieldMaxSizeExceededError, MaxDocumentsTransitionsExceededError, MissingPositionsInDocumentTypePropertiesError};
6666
use dpp::consensus::basic::group::GroupActionNotAllowedOnTransitionError;
6767
use dpp::consensus::basic::identity::{DataContractBoundsNotPresentError, DisablingKeyIdAlsoBeingAddedInSameTransitionError, InvalidIdentityCreditWithdrawalTransitionAmountError, InvalidIdentityUpdateTransitionDisableKeysError, InvalidIdentityUpdateTransitionEmptyError, TooManyMasterPublicKeyError, WithdrawalOutputScriptNotAllowedWhenSigningWithOwnerKeyError};
@@ -807,6 +807,9 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue {
807807
BasicError::InvalidTokenLanguageCodeError(e) => {
808808
generic_consensus_error!(InvalidTokenLanguageCodeError, e).into()
809809
}
810+
BasicError::MainGroupIsNotDefinedError(e) => {
811+
generic_consensus_error!(MainGroupIsNotDefinedError, e).into()
812+
}
810813
}
811814
}
812815

0 commit comments

Comments
 (0)