From 55a1e03273dd98797d43dff040f8e99827b9be3c Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Thu, 16 Jan 2025 15:30:42 +0700 Subject: [PATCH 1/2] feat(platform)!: token base support (#2383) --- .github/package-filters/js-packages.yml | 6 + .github/package-filters/rs-packages.yml | 5 + Cargo.lock | 60 +- Cargo.toml | 1 + Dockerfile | 4 + package.json | 4 +- packages/dapi-grpc/build.rs | 12 +- .../protos/platform/v0/platform.proto | 365 ++ packages/data-contracts/Cargo.toml | 1 + packages/data-contracts/src/error.rs | 17 + packages/data-contracts/src/lib.rs | 10 + .../meta_schemas/token/v0/token-meta.json | 245 + packages/rs-dpp/src/balances/credits.rs | 6 + packages/rs-dpp/src/balances/mod.rs | 1 + .../src/balances/total_tokens_balance/mod.rs | 53 + .../rs-dpp/src/data_contract/accessors/mod.rs | 176 +- .../src/data_contract/accessors/v1/mod.rs | 57 + .../src/data_contract/associated_token/mod.rs | 1 + .../token_configuration/accessors/mod.rs | 255 + .../token_configuration/accessors/v0/mod.rs | 105 + .../token_configuration/methods/mod.rs | 1 + .../mod.rs | 43 + .../v0/mod.rs | 283 + .../token_configuration/mod.rs | 33 + .../token_configuration/v0/accessors.rs | 191 + .../token_configuration/v0/mod.rs | 220 + .../authorized_action_takers.rs | 80 + .../data_contract/change_control_rules/mod.rs | 57 + .../change_control_rules/v0/mod.rs | 115 + .../src/data_contract/conversion/cbor/mod.rs | 16 +- .../src/data_contract/conversion/json/mod.rs | 11 +- .../src/data_contract/conversion/value/mod.rs | 8 +- .../mod.rs | 17 +- .../v0/mod.rs | 1 + .../v1/mod.rs | 66 + .../class_methods/try_from_schema/v0/mod.rs | 48 +- .../src/data_contract/document_type/mod.rs | 2 + .../document_type/property/mod.rs | 3 +- .../document_type/restricted_creation/mod.rs | 2 +- .../schema/enrich_with_base_schema/v0/mod.rs | 5 +- .../data_contract/extra/drive_api_tests.rs | 61 +- .../src/data_contract/factory/v0/mod.rs | 13 +- .../src/data_contract/group/accessors/mod.rs | 1 + .../data_contract/group/accessors/v0/mod.rs | 33 + .../rs-dpp/src/data_contract/group/mod.rs | 83 + .../rs-dpp/src/data_contract/group/v0/mod.rs | 68 + .../src/data_contract/methods/schema/mod.rs | 22 + packages/rs-dpp/src/data_contract/mod.rs | 71 +- .../data_contract/serialized_version/mod.rs | 173 +- .../serialized_version/v0/mod.rs | 33 +- .../serialized_version/v1/mod.rs | 136 + .../src/data_contract/v0/conversion/cbor.rs | 2 +- .../src/data_contract/v0/conversion/value.rs | 7 +- .../src/data_contract/v0/methods/schema.rs | 1 + .../data_contract/v0/serialization/bincode.rs | 31 - .../src/data_contract/v0/serialization/mod.rs | 117 +- .../src/data_contract/v1/accessors/mod.rs | 225 + .../src/data_contract/v1/conversion/cbor.rs | 98 + .../src/data_contract/v1/conversion/json.rs | 38 + .../src/data_contract/v1/conversion/mod.rs | 8 + .../src/data_contract/v1/conversion/value.rs | 78 + .../src/data_contract/v1/data_contract.rs | 75 + .../src/data_contract/v1/methods/mod.rs | 1 + .../src/data_contract/v1/methods/schema.rs | 198 + packages/rs-dpp/src/data_contract/v1/mod.rs | 7 + .../src/data_contract/v1/serialization/mod.rs | 194 + .../src/document/document_factory/mod.rs | 7 +- .../src/document/document_factory/v0/mod.rs | 18 +- packages/rs-dpp/src/document/errors.rs | 2 +- .../specialized_document_factory/mod.rs | 7 +- .../specialized_document_factory/v0/mod.rs | 18 +- .../src/errors/consensus/basic/basic_error.rs | 64 +- ...ntract_token_configuration_update_error.rs | 63 + .../invalid_token_base_supply_error.rs | 41 + .../consensus/basic/data_contract/mod.rs | 8 + ...ntiguous_contract_group_positions_error.rs | 52 + ...ntiguous_contract_token_positions_error.rs | 52 + ..._action_not_allowed_on_transition_error.rs | 31 + .../src/errors/consensus/basic/group/mod.rs | 3 + ...set_lock_transaction_is_not_found_error.rs | 12 - .../rs-dpp/src/errors/consensus/basic/mod.rs | 2 + ..._token_mint_recipient_not_allowed_error.rs | 31 + .../token/contract_has_no_tokens_error.rs | 31 + ...dentity_for_token_minting_not_set_error.rs | 33 + .../basic/token/invalid_action_id_error.rs | 43 + .../token/invalid_group_position_error.rs | 47 + .../basic/token/invalid_token_id_error.rs | 43 + .../token/invalid_token_position_error.rs | 47 + .../src/errors/consensus/basic/token/mod.rs | 17 + .../token_transfer_to_ourselves_error.rs | 44 + packages/rs-dpp/src/errors/consensus/codes.rs | 32 +- .../consensus/state/data_trigger/mod.rs | 2 +- .../group_action_already_completed_error.rs | 55 + ...action_already_signed_by_identity_error.rs | 64 + .../group_action_does_not_exist_error.rs | 56 + .../identity_not_member_of_group_error.rs | 56 + .../src/errors/consensus/state/group/mod.rs | 9 + .../errors/consensus/state/identity/mod.rs | 3 + ...recipient_identity_does_not_exist_error.rs | 31 + .../rs-dpp/src/errors/consensus/state/mod.rs | 2 + .../src/errors/consensus/state/state_error.rs | 33 +- ...oes_not_have_enough_token_balance_error.rs | 70 + .../identity_token_account_frozen_error.rs | 51 + ...identity_token_account_not_frozen_error.rs | 51 + .../src/errors/consensus/state/token/mod.rs | 9 + .../token/unauthorized_token_action_error.rs | 64 + packages/rs-dpp/src/errors/protocol_error.rs | 16 + packages/rs-dpp/src/group/action_event.rs | 12 + packages/rs-dpp/src/group/group_action/mod.rs | 14 + .../rs-dpp/src/group/group_action/v0/mod.rs | 12 + packages/rs-dpp/src/group/mod.rs | 66 + .../chain/chain_asset_lock_proof.rs | 1 - .../state_transition/asset_lock_proof/mod.rs | 2 +- packages/rs-dpp/src/lib.rs | 17 + .../rs-dpp/src/multi_identity_events/mod.rs | 7 + packages/rs-dpp/src/nft/mod.rs | 1 - packages/rs-dpp/src/state_transition/mod.rs | 82 +- .../src/state_transition/serialization.rs | 12 +- .../state_transition_types.rs | 2 +- .../batch_transition/accessors/mod.rs | 99 + .../batch_transition/accessors/v0/mod.rs | 19 + .../document_base_transition_trait.rs | 16 + .../document_base_transition/fields.rs | 2 +- .../document_base_transition/from_document.rs | 4 +- .../document_base_transition/mod.rs | 3 +- .../v0/from_document.rs | 4 +- .../document_base_transition/v0/mod.rs | 2 +- .../document_base_transition/v0/v0_methods.rs | 2 +- .../document_base_transition/v0_methods.rs | 4 +- .../document_create_transition/convertible.rs | 14 +- .../from_document.rs | 4 +- .../document_create_transition/mod.rs | 2 +- .../v0/from_document.rs | 4 +- .../document_create_transition/v0/mod.rs | 16 +- .../v0/v0_methods.rs | 24 +- .../document_create_transition/v0_methods.rs | 11 +- .../from_document.rs | 4 +- .../document_delete_transition/mod.rs | 0 .../v0/from_document.rs | 10 +- .../document_delete_transition/v0/mod.rs | 2 +- .../v0/v0_methods.rs | 17 + .../document_delete_transition/v0_methods.rs | 8 +- .../from_document.rs | 4 +- .../document_purchase_transition/mod.rs | 0 .../v0/from_document.rs | 10 +- .../document_purchase_transition/v0/mod.rs | 2 +- .../v0/v0_methods.rs | 24 +- .../v0_methods.rs | 11 +- .../from_document.rs | 10 +- .../document_replace_transition/mod.rs | 0 .../v0/from_document.rs | 10 +- .../document_replace_transition/v0/mod.rs | 4 +- .../v0/v0_methods.rs | 21 +- .../document_replace_transition/v0_methods.rs | 11 +- .../from_document.rs | 12 +- .../document_transfer_transition/mod.rs | 0 .../v0/from_document.rs | 12 +- .../document_transfer_transition/v0/mod.rs | 2 +- .../v0/v0_methods.rs | 21 +- .../v0_methods.rs | 11 +- .../document_transition.rs} | 158 +- .../document_transition_action_type.rs} | 8 +- .../from_document.rs | 4 +- .../document_update_price_transition/mod.rs | 0 .../v0/from_document.rs | 4 +- .../v0/mod.rs | 2 +- .../v0/v0_methods.rs | 21 +- .../v0_methods.rs | 11 +- .../batched_transition/mod.rs | 140 + .../batched_transition/multi_party_action.rs | 5 + .../batched_transition/resolvers.rs | 185 + .../token_base_transition/fields.rs | 12 + .../token_base_transition/mod.rs | 106 + .../token_base_transition_accessors.rs | 16 + .../token_base_transition/v0/mod.rs | 117 + .../token_base_transition/v0/v0_methods.rs | 102 + .../token_base_transition/v0_methods.rs | 86 + .../token_burn_transition/mod.rs | 24 + .../token_burn_transition/v0/mod.rs | 38 + .../token_burn_transition/v0/v0_methods.rs | 76 + .../token_burn_transition/v0_methods.rs | 66 + .../mod.rs | 25 + .../v0/mod.rs | 25 + .../v0/v0_methods.rs | 78 + .../v0_methods.rs | 87 + .../token_emergency_action_transition/mod.rs | 25 + .../v0/mod.rs | 30 + .../v0/v0_methods.rs | 80 + .../v0_methods.rs | 86 + .../token_freeze_transition/mod.rs | 24 + .../token_freeze_transition/v0/mod.rs | 45 + .../token_freeze_transition/v0/v0_methods.rs | 78 + .../token_freeze_transition/v0_methods.rs | 85 + .../token_mint_transition/mod.rs | 24 + .../token_mint_transition/v0/mod.rs | 59 + .../token_mint_transition/v0/v0_methods.rs | 86 + .../token_mint_transition/v0_methods.rs | 98 + .../token_transfer_transition/mod.rs | 18 + .../token_transfer_transition/v0/mod.rs | 67 + .../v0/v0_methods.rs | 195 + .../token_transfer_transition/v0_methods.rs | 156 + .../batched_transition/token_transition.rs | 218 + .../token_transition_action_type.rs | 71 + .../token_unfreeze_transition/mod.rs | 24 + .../token_unfreeze_transition/v0/mod.rs | 45 + .../v0/v0_methods.rs | 78 + .../token_unfreeze_transition/v0_methods.rs | 85 + .../fields.rs | 2 +- .../batch_transition/identity_signed.rs | 26 + .../json_conversion.rs | 17 +- .../document/batch_transition/methods/mod.rs | 862 ++++ .../methods/v0/mod.rs | 35 +- .../batch_transition/methods/v1/mod.rs | 157 + .../document/batch_transition/mod.rs | 115 + .../batch_transition/resolvers/mod.rs | 1 + .../batch_transition/resolvers/v0/mod.rs | 26 + .../batch_transition/state_transition_like.rs | 79 + .../v0/cbor_conversion.rs | 0 .../v0/identity_signed.rs | 4 +- .../batch_transition/v0/json_conversion.rs | 4 + .../v0/mod.rs | 4 +- .../v0/state_transition_like.rs | 20 +- .../v0/types.rs | 8 +- .../v0/v0_methods.rs | 90 +- .../batch_transition/v0/value_conversion.rs | 4 + .../v0/version.rs | 4 +- .../batch_transition/v1/identity_signed.rs | 23 + .../batch_transition/v1/json_conversion.rs | 4 + .../document/batch_transition/v1/mod.rs | 37 + .../v1/state_transition_like.rs | 92 + .../document/batch_transition/v1/types.rs | 18 + .../batch_transition/v1/v0_methods.rs | 894 ++++ .../batch_transition/v1/value_conversion.rs | 4 + .../document/batch_transition/v1/version.rs | 9 + .../validation/find_duplicates_by_id/mod.rs | 2 +- .../find_duplicates_by_id/v0/mod.rs | 23 +- .../validation/mod.rs | 0 .../validate_basic_structure/mod.rs | 4 +- .../validate_basic_structure/v0/mod.rs | 191 + .../value_conversion.rs | 51 +- .../document/batch_transition/version.rs | 12 + .../accessors/mod.rs | 19 - .../accessors/v0/mod.rs | 6 - .../v0/v0_methods.rs | 29 - .../identity_signed.rs | 27 - .../documents_batch_transition/methods/mod.rs | 326 -- .../documents_batch_transition/mod.rs | 598 --- .../state_transition_like.rs | 71 - .../v0/json_conversion.rs | 4 - .../v0/value_conversion.rs | 4 - .../validate_basic_structure/v0/mod.rs | 104 - .../documents_batch_transition/version.rs | 11 - .../state_transitions/document/mod.rs | 2 +- .../methods/v0/mod.rs | 4 +- .../v0/v0_methods.rs | 2 + .../value_conversion.rs | 2 +- .../traits/state_transition_like.rs | 3 +- .../get_document_transitions_fixture.rs | 17 +- .../rs-dpp/src/tokens/allowed_currency.rs | 7 + .../rs-dpp/src/tokens/emergency_action.rs | 30 + packages/rs-dpp/src/tokens/errors.rs | 9 + packages/rs-dpp/src/tokens/info/methods.rs | 16 + packages/rs-dpp/src/tokens/info/mod.rs | 44 + packages/rs-dpp/src/tokens/info/v0/mod.rs | 26 + packages/rs-dpp/src/tokens/mod.rs | 16 + packages/rs-dpp/src/tokens/status/methods.rs | 16 + packages/rs-dpp/src/tokens/status/mod.rs | 44 + packages/rs-dpp/src/tokens/status/v0/mod.rs | 26 + packages/rs-dpp/src/tokens/token_event.rs | 205 + .../src/validation/meta_validators/mod.rs | 65 +- .../contender_structs/contender/v0/mod.rs | 2 +- .../src/voting/contender_structs/mod.rs | 2 +- .../mod.rs | 2 +- .../mod.rs | 2 +- packages/rs-dpp/src/voting/vote_polls/mod.rs | 2 +- .../src/voting/votes/resource_vote/mod.rs | 2 +- packages/rs-drive-abci/src/config.rs | 9 + .../src/execution/check_tx/v0/mod.rs | 940 +++- .../engine/run_block_proposal/v0/mod.rs | 2 +- .../mod.rs | 0 .../v0/mod.rs | 0 .../mod.rs | 2 +- .../mod.rs | 17 +- .../v0/mod.rs | 4 +- .../v1/mod.rs | 54 + .../tests.rs | 42 +- .../create_genesis_state/common.rs | 101 + .../create_genesis_state/mod.rs | 10 +- .../create_genesis_state/v0/mod.rs | 93 +- .../create_genesis_state/v1/mod.rs | 125 + .../src/execution/platform_events/mod.rs | 3 +- .../v0/mod.rs | 84 +- .../execution/platform_events/tokens/mod.rs | 1 + .../validate_token_aggregated_balance/mod.rs | 54 + .../v0/mod.rs | 37 + .../v0/mod.rs | 4 +- .../execution/types/execution_event/mod.rs | 2 +- .../types/execution_operation/mod.rs | 14 + .../v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../state_transition/processor/v0/mod.rs | 28 +- .../document_create_transition_action/mod.rs | 12 +- .../state_v0/mod.rs | 8 +- .../state_v1/mod.rs | 8 +- .../structure_v0/mod.rs | 4 +- .../document_delete_transition_action/mod.rs | 10 +- .../state_v0/mod.rs | 8 +- .../structure_v0/mod.rs | 6 +- .../mod.rs | 10 +- .../state_v0/mod.rs | 4 +- .../structure_v0/mod.rs | 4 +- .../document_replace_transition_action/mod.rs | 10 +- .../state_v0/mod.rs | 4 +- .../structure_v0/mod.rs | 4 +- .../mod.rs | 10 +- .../state_v0/mod.rs | 4 +- .../structure_v0/mod.rs | 4 +- .../mod.rs | 10 +- .../state_v0/mod.rs | 4 +- .../structure_v0/mod.rs | 4 +- .../batch/action_validation/mod.rs | 14 + .../token_base_transition_action/mod.rs | 86 + .../state_v0/mod.rs | 67 + .../structure_v0/mod.rs | 49 + .../token_burn_transition_action/mod.rs | 86 + .../state_v0/mod.rs | 108 + .../structure_v0/mod.rs | 25 + .../mod.rs | 86 + .../state_v0/mod.rs | 109 + .../structure_v0/mod.rs | 27 + .../mod.rs | 86 + .../state_v0/mod.rs | 83 + .../structure_v0/mod.rs | 27 + .../token_freeze_transition_action/mod.rs | 86 + .../state_v0/mod.rs | 81 + .../structure_v0/mod.rs | 25 + .../token_mint_transition_action/mod.rs | 86 + .../state_v0/mod.rs | 166 + .../structure_v0/mod.rs | 25 + .../token_transfer_transition_action/mod.rs | 88 + .../state_v0/mod.rs | 103 + .../structure_v0/mod.rs | 29 + .../token_unfreeze_transition_action/mod.rs | 86 + .../state_v0/mod.rs | 107 + .../structure_v0/mod.rs | 25 + .../advanced_structure/mod.rs | 0 .../batch/advanced_structure/v0/mod.rs | 339 ++ .../{documents_batch => batch}/balance/mod.rs | 8 +- .../balance/v0/mod.rs | 15 +- .../bindings/data_trigger_binding/mod.rs | 4 +- .../bindings/data_trigger_binding/v0/mod.rs | 4 +- .../data_triggers/bindings/list/mod.rs | 4 +- .../data_triggers/bindings/list/v0/mod.rs | 12 +- .../data_triggers/bindings/mod.rs | 0 .../data_triggers/context.rs | 0 .../data_triggers/executor.rs | 27 +- .../data_triggers/mod.rs | 2 +- .../data_triggers/triggers/dashpay/mod.rs | 8 +- .../data_triggers/triggers/dashpay/v0/mod.rs | 50 +- .../data_triggers/triggers/dpns/mod.rs | 14 +- .../data_triggers/triggers/dpns/v0/mod.rs | 105 +- .../triggers/feature_flags/mod.rs | 8 +- .../triggers/feature_flags/v0/mod.rs | 34 +- .../data_triggers/triggers/mod.rs | 0 .../data_triggers/triggers/reject/mod.rs | 14 +- .../data_triggers/triggers/reject/v0/mod.rs | 21 +- .../data_triggers/triggers/withdrawals/mod.rs | 8 +- .../triggers/withdrawals/v0/mod.rs | 28 +- .../identity_contract_nonce/mod.rs | 0 .../identity_contract_nonce/v0/mod.rs | 11 +- .../is_allowed/mod.rs | 8 +- .../is_allowed/v0/mod.rs | 11 +- .../{documents_batch => batch}/mod.rs | 4553 ++++++++++++++++- .../{documents_batch => batch}/state/mod.rs | 0 .../state/v0/data_triggers.rs | 10 +- .../state/v0/fetch_contender.rs | 0 .../state/v0/fetch_documents.rs | 4 +- .../state_transitions/batch/state/v0/mod.rs | 302 ++ .../transformer/mod.rs | 0 .../transformer/v0/mod.rs | 394 +- .../advanced_structure/v0/mod.rs | 36 +- .../data_contract_create/mod.rs | 266 + .../data_contract_create/state/v0/mod.rs | 109 +- .../data_contract_update/state/v0/mod.rs | 14 +- .../documents_batch/action_validation/mod.rs | 6 - .../advanced_structure/v0/mod.rs | 219 - .../documents_batch/state/v0/mod.rs | 231 - .../state_transitions/identity_create/mod.rs | 601 ++- .../state_transitions/identity_top_up/mod.rs | 135 +- .../state_transition/state_transitions/mod.rs | 77 +- .../state_transition/transformer/mod.rs | 2 +- packages/rs-drive-abci/src/main.rs | 4 +- .../src/platform_types/platform/mod.rs | 16 +- .../v0/for_saving.rs | 3 +- .../v0/for_saving_v1.rs | 3 +- .../src/query/group_queries/group_info/mod.rs | 53 + .../query/group_queries/group_info/v0/mod.rs | 95 + .../query/group_queries/group_infos/mod.rs | 53 + .../query/group_queries/group_infos/v0/mod.rs | 127 + .../src/query/group_queries/mod.rs | 2 + packages/rs-drive-abci/src/query/mod.rs | 2 + packages/rs-drive-abci/src/query/service.rs | 107 +- .../identities_token_balances/mod.rs | 66 + .../identities_token_balances/v0/mod.rs | 88 + .../identities_token_infos/mod.rs | 62 + .../identities_token_infos/v0/mod.rs | 94 + .../identity_token_balances/mod.rs | 62 + .../identity_token_balances/v0/mod.rs | 86 + .../token_queries/identity_token_infos/mod.rs | 62 + .../identity_token_infos/v0/mod.rs | 89 + .../src/query/token_queries/mod.rs | 5 + .../query/token_queries/token_status/mod.rs | 59 + .../token_queries/token_status/v0/mod.rs | 73 + .../tests/strategy_tests/main.rs | 115 +- .../tests/strategy_tests/strategy.rs | 305 +- .../tests/strategy_tests/token_tests.rs | 329 ++ .../verify_state_transitions.rs | 625 ++- .../tests/strategy_tests/voting_tests.rs | 159 +- .../contract/basic-token/basic-token.json | 18 + .../crypto-card-game-in-game-currency.json | 135 + packages/rs-drive/Cargo.toml | 13 +- .../rs-drive/src/cache/system_contracts.rs | 11 + .../v0/mod.rs | 9 +- .../fetch_asset_lock_outpoint_info/v0/mod.rs | 4 +- packages/rs-drive/src/drive/balances/mod.rs | 60 +- .../v0/mod.rs | 5 +- .../v0/mod.rs | 8 +- .../insert/add_contract_to_storage/v0/mod.rs | 8 +- .../contract/insert/insert_contract/mod.rs | 18 +- .../contract/insert/insert_contract/v0/mod.rs | 2 +- .../contract/insert/insert_contract/v1/mod.rs | 278 + .../contract/update/update_contract/mod.rs | 34 +- .../contract/update/update_contract/v0/mod.rs | 10 +- .../contract/update/update_contract/v1/mod.rs | 253 + .../credit_pools/epochs/operations_factory.rs | 20 +- .../v0/mod.rs | 2 +- .../get_unpaid_epoch_index/v0/mod.rs | 2 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../rs-drive/src/drive/document/delete/mod.rs | 24 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 8 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 8 +- .../mod.rs | 6 +- .../v0/mod.rs | 6 +- .../mod.rs | 2 +- .../v0/mod.rs | 4 +- .../mod.rs | 2 +- .../v0/mod.rs | 4 +- .../mod.rs | 2 +- .../v0/mod.rs | 4 +- .../mod.rs | 2 +- .../v0/mod.rs | 4 +- .../mod.rs | 2 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../add_document_to_primary_storage/v0/mod.rs | 10 +- .../v0/mod.rs | 14 +- .../v0/mod.rs | 12 +- .../v0/mod.rs | 12 +- .../rs-drive/src/drive/document/insert/mod.rs | 25 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 18 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 12 +- .../v0/mod.rs | 12 +- .../v0/mod.rs | 14 +- .../rs-drive/src/drive/document/update/mod.rs | 54 +- .../for_add_group_action/mod.rs | 79 + .../for_add_group_action/v0/mod.rs | 173 + .../src/drive/group/estimated_costs/mod.rs | 1 + .../fetch/fetch_action_id_has_signer/mod.rs | 118 + .../fetch_action_id_has_signer/v0/mod.rs | 165 + .../group/fetch/fetch_action_id_info/mod.rs | 121 + .../fetch/fetch_action_id_info/v0/mod.rs | 91 + .../mod.rs | 120 + .../v0/mod.rs | 132 + .../fetch_action_id_signers_power/mod.rs | 78 + .../fetch_action_id_signers_power/v0/mod.rs | 132 + .../drive/group/fetch/fetch_group_info/mod.rs | 103 + .../group/fetch/fetch_group_info/v0/mod.rs | 83 + .../group/fetch/fetch_group_infos/mod.rs | 99 + .../group/fetch/fetch_group_infos/v0/mod.rs | 79 + .../rs-drive/src/drive/group/fetch/mod.rs | 7 + .../rs-drive/src/drive/group/fetch/queries.rs | 47 + .../group/insert/add_group_action/mod.rs | 128 + .../group/insert/add_group_action/v0/mod.rs | 244 + .../drive/group/insert/add_new_groups/mod.rs | 99 + .../group/insert/add_new_groups/v0/mod.rs | 217 + .../rs-drive/src/drive/group/insert/mod.rs | 2 + packages/rs-drive/src/drive/group/mod.rs | 10 + packages/rs-drive/src/drive/group/paths.rs | 256 + .../rs-drive/src/drive/group/prove/mod.rs | 2 + .../drive/group/prove/prove_group_info/mod.rs | 99 + .../group/prove/prove_group_info/v0/mod.rs | 45 + .../group/prove/prove_group_infos/mod.rs | 99 + .../group/prove/prove_group_infos/v0/mod.rs | 50 + .../fetch_identity_contract_nonce/v0/mod.rs | 4 +- .../merge_identity_contract_nonce/v0/mod.rs | 12 +- .../v0/mod.rs | 10 +- .../v0/mod.rs | 4 +- .../estimation_costs/for_balances/v0/mod.rs | 9 +- .../for_identity_contract_info/v0/mod.rs | 10 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../for_keys_for_identity_id/v0/mod.rs | 10 +- .../for_negative_credit/v0/mod.rs | 6 +- .../v0/mod.rs | 4 +- .../for_root_key_reference_tree/v0/mod.rs | 4 +- .../for_update_nonce/v0/mod.rs | 8 +- .../for_update_revision/v0/mod.rs | 8 +- .../balance/fetch_identity_balance/v0/mod.rs | 4 +- .../fetch_identity_negative_balance/v0/mod.rs | 4 +- .../fetch/fetch_by_public_key_hashes/mod.rs | 2 +- .../nonce/fetch_identity_nonce/v0/mod.rs | 4 +- .../fetch_identity_revision/v0/mod.rs | 4 +- .../identity/insert/add_new_identity/mod.rs | 6 +- .../insert/add_new_identity/v0/mod.rs | 10 +- .../src/drive/identity/key/fetch/mod.rs | 8 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 4 +- .../rs-drive/src/drive/identity/update/mod.rs | 29 +- .../merge_identity_nonce_operations/v0/mod.rs | 2 +- .../rs-drive/src/drive/initialization/mod.rs | 4 +- .../src/drive/initialization/v0/mod.rs | 385 +- .../src/drive/initialization/v1/mod.rs | 81 + packages/rs-drive/src/drive/mod.rs | 29 +- .../v1/mod.rs | 4 +- .../v1/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 11 +- .../fetch/single_balance/v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 19 +- .../v0/mod.rs | 15 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 6 +- .../for_total_system_credits_update/v0/mod.rs | 9 +- .../src/drive/system/genesis_time/mod.rs | 6 +- .../add_transaction_history_operations/mod.rs | 55 + .../v0/mod.rs | 61 + .../src/drive/tokens/apply_status/mod.rs | 93 + .../src/drive/tokens/apply_status/v0/mod.rs | 107 + .../add_to_previous_token_balance/mod.rs | 119 + .../add_to_previous_token_balance/v0/mod.rs | 141 + .../fetch_identities_token_balances/mod.rs | 152 + .../fetch_identities_token_balances/v0/mod.rs | 63 + .../fetch_identity_token_balance/mod.rs | 135 + .../fetch_identity_token_balance/v0/mod.rs | 83 + .../fetch_identity_token_balances/mod.rs | 151 + .../fetch_identity_token_balances/v0/mod.rs | 83 + .../rs-drive/src/drive/tokens/balance/mod.rs | 17 + .../prove_identities_token_balances/mod.rs | 149 + .../prove_identities_token_balances/v0/mod.rs | 359 ++ .../prove_identity_token_balances/mod.rs | 149 + .../prove_identity_token_balances/v0/mod.rs | 55 + .../src/drive/tokens/balance/queries.rs | 72 + .../remove_from_identity_token_balance/mod.rs | 117 + .../v0/mod.rs | 129 + .../src/drive/tokens/balance/update.rs | 896 ++++ .../rs-drive/src/drive/tokens/burn/mod.rs | 100 + .../rs-drive/src/drive/tokens/burn/v0/mod.rs | 108 + .../calculate_total_tokens_balance/mod.rs | 42 + .../calculate_total_tokens_balance/v0/mod.rs | 47 + .../estimated_costs/for_token_balances/mod.rs | 57 + .../for_token_balances/v0/mod.rs | 102 + .../for_token_identity_infos/mod.rs | 57 + .../for_token_identity_infos/v0/mod.rs | 81 + .../for_token_status_infos/mod.rs | 55 + .../for_token_status_infos/v0/mod.rs | 68 + .../for_token_total_supply/mod.rs | 50 + .../for_token_total_supply/v0/mod.rs | 101 + .../src/drive/tokens/estimated_costs/mod.rs | 11 + .../rs-drive/src/drive/tokens/freeze/mod.rs | 95 + .../src/drive/tokens/freeze/v0/mod.rs | 147 + .../info/fetch_identities_token_infos/mod.rs | 151 + .../fetch_identities_token_infos/v0/mod.rs | 66 + .../info/fetch_identity_token_info/mod.rs | 134 + .../info/fetch_identity_token_info/v0/mod.rs | 73 + .../info/fetch_identity_token_infos/mod.rs | 151 + .../info/fetch_identity_token_infos/v0/mod.rs | 87 + .../rs-drive/src/drive/tokens/info/mod.rs | 12 + .../info/prove_identities_token_infos/mod.rs | 149 + .../prove_identities_token_infos/v0/mod.rs | 353 ++ .../info/prove_identity_token_infos/mod.rs | 149 + .../info/prove_identity_token_infos/v0/mod.rs | 55 + .../rs-drive/src/drive/tokens/info/queries.rs | 72 + .../rs-drive/src/drive/tokens/mint/mod.rs | 106 + .../rs-drive/src/drive/tokens/mint/v0/mod.rs | 115 + packages/rs-drive/src/drive/tokens/mod.rs | 54 + packages/rs-drive/src/drive/tokens/paths.rs | 105 + .../tokens/status/fetch_token_status/mod.rs | 110 + .../status/fetch_token_status/v0/mod.rs | 70 + .../tokens/status/fetch_token_statuses/mod.rs | 126 + .../status/fetch_token_statuses/v0/mod.rs | 76 + .../rs-drive/src/drive/tokens/status/mod.rs | 7 + .../tokens/status/prove_token_statuses/mod.rs | 124 + .../status/prove_token_statuses/v0/mod.rs | 52 + .../system/add_to_token_total_supply/mod.rs | 119 + .../add_to_token_total_supply/v0/mod.rs | 148 + .../tokens/system/create_token_trees/mod.rs | 124 + .../system/create_token_trees/v0/mod.rs | 220 + .../rs-drive/src/drive/tokens/system/mod.rs | 3 + .../remove_from_token_total_supply/mod.rs | 112 + .../remove_from_token_total_supply/v0/mod.rs | 128 + .../rs-drive/src/drive/tokens/transfer/mod.rs | 106 + .../src/drive/tokens/transfer/v0/mod.rs | 114 + .../rs-drive/src/drive/tokens/unfreeze/mod.rs | 95 + .../src/drive/tokens/unfreeze/v0/mod.rs | 147 + .../v0/mod.rs | 6 +- .../v0/mod.rs | 4 +- .../v1/mod.rs | 8 +- .../v0/mod.rs | 6 +- .../v1/mod.rs | 6 +- .../v0/mod.rs | 4 +- .../v1/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 4 +- .../v0/mod.rs | 6 +- .../v0/mod.rs | 14 +- .../resolve.rs | 2 + packages/rs-drive/src/fees/op.rs | 98 +- packages/rs-drive/src/open/mod.rs | 21 +- ..._resource_votes_given_by_identity_query.rs | 6 + .../query/drive_contested_document_query.rs | 2 + packages/rs-drive/src/query/mod.rs | 14 +- .../src/query/vote_poll_vote_state_query.rs | 2 + .../batch/batch_transition.rs | 28 + .../document/document_create_transition.rs | 10 +- .../document/document_delete_transition.rs | 12 +- .../document/document_purchase_transition.rs | 10 +- .../document/document_replace_transition.rs | 10 +- .../document/document_transfer_transition.rs | 10 +- .../document/document_transition.rs | 25 +- .../document_update_price_transition.rs | 10 +- .../document/documents_batch_transition.rs | 8 +- .../batch/document/mod.rs | 8 + .../{document => batch}/mod.rs | 15 +- .../batch/token/mod.rs | 8 + .../batch/token/token_burn_transition.rs | 102 + .../token_destroy_frozen_funds_transition.rs | 107 + .../token_emergency_action_transition.rs | 105 + .../batch/token/token_freeze_transition.rs | 105 + .../batch/token/token_mint_transition.rs | 111 + .../batch/token/token_transfer_transition.rs | 84 + .../batch/token/token_transition.rs | 105 + .../batch/token/token_unfreeze_transition.rs | 107 + .../action_convert_to_operations/mod.rs | 4 +- .../document_base_transition_action/mod.rs | 0 .../transformer.rs | 8 +- .../document_base_transition_action/v0/mod.rs | 0 .../v0/transformer.rs | 4 +- .../document_create_transition_action/mod.rs | 2 +- .../transformer.rs | 8 +- .../v0/mod.rs | 2 +- .../v0/transformer.rs | 10 +- .../document_delete_transition_action/mod.rs | 4 +- .../transformer.rs | 8 +- .../v0/mod.rs | 2 +- .../v0/transformer.rs | 10 +- .../mod.rs | 2 +- .../transformer.rs | 4 +- .../v0/mod.rs | 2 +- .../v0/transformer.rs | 8 +- .../document_replace_transition_action/mod.rs | 2 +- .../transformer.rs | 4 +- .../v0/mod.rs | 2 +- .../v0/transformer.rs | 8 +- .../mod.rs | 2 +- .../transformer.rs | 4 +- .../v0/mod.rs | 2 +- .../v0/transformer.rs | 8 +- .../document_transition_action_type.rs} | 11 +- .../mod.rs | 2 +- .../transformer.rs | 4 +- .../v0/mod.rs | 2 +- .../v0/transformer.rs | 8 +- .../document_transition/mod.rs | 54 +- .../batch/batched_transition/mod.rs | 40 + .../token_transition/mod.rs | 144 + .../token_base_transition_action/mod.rs | 79 + .../transformer.rs | 69 + .../token_base_transition_action/v0/mod.rs | 112 + .../v0/transformer.rs | 242 + .../token_burn_transition_action/mod.rs | 60 + .../transformer.rs | 125 + .../token_burn_transition_action/v0/mod.rs | 102 + .../v0/transformer.rs | 229 + .../mod.rs | 76 + .../transformer.rs | 117 + .../v0/mod.rs | 115 + .../v0/transformer.rs | 311 ++ .../mod.rs | 63 + .../transformer.rs | 117 + .../v0/mod.rs | 97 + .../v0/transformer.rs | 232 + .../token_freeze_transition_action/mod.rs | 61 + .../transformer.rs | 117 + .../token_freeze_transition_action/v0/mod.rs | 96 + .../v0/transformer.rs | 232 + .../token_mint_transition_action/mod.rs | 73 + .../transformer.rs | 117 + .../token_mint_transition_action/v0/mod.rs | 112 + .../v0/transformer.rs | 367 ++ .../token_transfer_transition_action/mod.rs | 157 + .../transformer.rs | 112 + .../v0/mod.rs | 266 + .../v0/transformer.rs | 177 + .../token_transition_action_type.rs | 22 + .../token_unfreeze_transition_action/mod.rs | 61 + .../transformer.rs | 117 + .../v0/mod.rs | 96 + .../v0/transformer.rs | 232 + .../documents_batch => batch}/mod.rs | 86 +- .../documents_batch => batch}/v0/mod.rs | 39 +- .../state_transition_action/document/mod.rs | 2 - .../src/state_transition_action/mod.rs | 12 +- .../transformer.rs | 173 +- .../v0/transformer.rs | 90 +- .../v0/mod.rs | 2 +- .../src/util/batch/drive_op_batch/group.rs | 68 + .../src/util/batch/drive_op_batch/mod.rs | 37 +- .../src/util/batch/drive_op_batch/token.rs | 212 + .../util/batch/drive_op_batch/withdrawals.rs | 8 +- .../src/util/batch/grovedb_op_batch/mod.rs | 12 +- .../grove_operations/batch_delete/v0/mod.rs | 2 +- .../v0/mod.rs | 16 +- .../batch_insert_empty_sum_tree/mod.rs | 52 + .../batch_insert_empty_sum_tree/v0/mod.rs | 53 + .../mod.rs | 6 +- .../v0/mod.rs | 86 +- .../batch_insert_if_changed_value/v0/mod.rs | 3 +- .../batch_insert_if_not_exists/v0/mod.rs | 3 +- .../v0/mod.rs | 3 +- .../mod.rs | 71 + .../v0/mod.rs | 230 + .../v0/mod.rs | 4 +- .../batch_move_items_in_path_query/v0/mod.rs | 18 +- .../batch_remove_raw/v0/mod.rs | 6 +- .../v0/mod.rs | 2 +- .../grove_apply_operation/v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../grove_batch_operations_costs/v0/mod.rs | 2 +- .../grove_operations/grove_clear/v0/mod.rs | 2 +- .../grove_operations/grove_delete/v0/mod.rs | 2 +- .../util/grove_operations/grove_get/v0/mod.rs | 8 +- .../grove_get_big_sum_tree_total_value/mod.rs | 58 + .../v0/mod.rs | 67 + .../mod.rs | 58 + .../v0/mod.rs | 72 + .../grove_get_path_query/v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../grove_get_proved_path_query/v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../grove_operations/grove_get_raw/v0/mod.rs | 8 +- .../grove_get_raw_item/mod.rs | 55 + .../grove_get_raw_item/v0/mod.rs | 83 + .../grove_get_raw_optional/v0/mod.rs | 6 +- .../grove_get_raw_optional_item/mod.rs | 59 + .../grove_get_raw_optional_item/v0/mod.rs | 84 + .../grove_get_raw_path_query/v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../grove_get_sum_tree_total_value/v0/mod.rs | 6 +- .../grove_operations/grove_has_raw/v0/mod.rs | 8 +- .../grove_operations/grove_insert/v0/mod.rs | 2 +- .../grove_insert_empty_sum_tree/v0/mod.rs | 2 +- .../grove_insert_empty_tree/v0/mod.rs | 2 +- .../grove_insert_if_not_exists/v0/mod.rs | 2 +- .../v0/mod.rs | 2 +- .../rs-drive/src/util/grove_operations/mod.rs | 83 +- .../util/object_size_info/contract_info.rs | 5 + .../apply_batch_grovedb_operations/v0/mod.rs | 2 +- .../rs-drive/src/util/test_helpers/mod.rs | 13 +- .../rs-drive/src/util/test_helpers/setup.rs | 19 +- packages/rs-drive/src/util/type_constants.rs | 2 + packages/rs-drive/src/verify/mod.rs | 1 + .../v0/mod.rs | 346 +- packages/rs-drive/src/verify/tokens/mod.rs | 2 + .../mod.rs | 80 + .../v0/mod.rs | 71 + .../mod.rs | 79 + .../v0/mod.rs | 65 + .../rs-drive/tests/deterministic_root_hash.rs | 41 +- packages/rs-drive/tests/query_tests.rs | 1708 ++++++- .../rs-drive/tests/query_tests_history.rs | 1409 ++++- .../tokens/token-example-contract.json | 23 + packages/rs-platform-version/Cargo.toml | 2 +- .../dpp_versions/dpp_contract_versions/mod.rs | 1 + .../dpp_versions/dpp_contract_versions/v2.rs | 54 + .../mod.rs | 3 +- .../v1.rs | 2 +- .../v2.rs | 105 + .../dpp_versions/dpp_token_versions/mod.rs | 9 + .../dpp_versions/dpp_token_versions/v1.rs | 6 + .../dpp_validation_versions/mod.rs | 1 + .../dpp_validation_versions/v1.rs | 1 + .../dpp_validation_versions/v2.rs | 1 + .../src/version/dpp_versions/mod.rs | 3 + .../drive_abci_method_versions/mod.rs | 9 +- .../drive_abci_method_versions/v1.rs | 8 +- .../drive_abci_method_versions/v2.rs | 8 +- .../drive_abci_method_versions/v3.rs | 8 +- .../drive_abci_method_versions/v4.rs | 8 +- .../drive_abci_method_versions/v5.rs | 8 +- .../drive_abci_method_versions/v6.rs | 126 + .../drive_abci_query_versions/mod.rs | 17 + .../drive_abci_query_versions/v1.rs | 46 +- .../drive_abci_validation_versions/mod.rs | 17 +- .../drive_abci_validation_versions/v1.rs | 17 +- .../drive_abci_validation_versions/v2.rs | 17 +- .../drive_abci_validation_versions/v3.rs | 17 +- .../drive_abci_validation_versions/v4.rs | 17 +- .../drive_abci_validation_versions/v5.rs | 17 +- .../drive_contract_method_versions/mod.rs | 1 + .../drive_contract_method_versions/v2.rs | 33 + .../drive_group_method_versions/mod.rs | 38 + .../drive_group_method_versions/v1.rs | 26 + .../drive_grove_method_versions/mod.rs | 6 + .../drive_grove_method_versions/v1.rs | 6 + .../drive_identity_method_versions/mod.rs | 3 + .../drive_identity_method_versions/v1.rs | 3 + .../mod.rs | 7 + .../v1.rs | 7 + .../drive_token_method_versions/mod.rs | 50 + .../drive_token_method_versions/v1.rs | 41 + .../drive_verify_method_versions/mod.rs | 8 + .../drive_verify_method_versions/v1.rs | 7 +- .../src/version/drive_versions/mod.rs | 7 + .../src/version/drive_versions/v1.rs | 4 + .../src/version/drive_versions/v2.rs | 4 + .../src/version/drive_versions/v3.rs | 4 + .../src/version/drive_versions/v4.rs | 105 + .../src/version/fee/processing/mod.rs | 4 + .../src/version/fee/processing/v1.rs | 1 + .../src/version/mocks/v2_test.rs | 52 +- .../src/version/mocks/v3_test.rs | 10 +- .../rs-platform-version/src/version/mod.rs | 5 +- .../src/version/protocol_version.rs | 5 +- .../rs-platform-version/src/version/v1.rs | 2 + .../rs-platform-version/src/version/v2.rs | 2 + .../rs-platform-version/src/version/v3.rs | 2 + .../rs-platform-version/src/version/v4.rs | 2 + .../rs-platform-version/src/version/v5.rs | 2 + .../rs-platform-version/src/version/v6.rs | 2 + .../rs-platform-version/src/version/v7.rs | 2 + .../rs-platform-version/src/version/v8.rs | 2 + .../rs-platform-version/src/version/v9.rs | 66 + .../platform/transition/purchase_document.rs | 6 +- .../src/platform/transition/put_document.rs | 6 +- .../platform/transition/transfer_document.rs | 6 +- .../transition/update_price_of_document.rs | 32 +- .../src/platform/transition/waitable.rs | 2 +- packages/search-contract/.eslintrc | 18 + packages/search-contract/.mocharc.yml | 2 + packages/search-contract/Cargo.toml | 13 + packages/search-contract/LICENSE | 20 + packages/search-contract/README.md | 26 + packages/search-contract/lib/systemIds.js | 4 + packages/search-contract/package.json | 29 + .../schema/v1/search-contract-documents.json | 62 + packages/search-contract/src/error.rs | 17 + packages/search-contract/src/lib.rs | 37 + packages/search-contract/src/v1/mod.rs | 27 + packages/search-contract/test/.eslintrc | 12 + packages/search-contract/test/bootstrap.js | 30 + .../test/unit/searchContract.spec.js | 187 + packages/strategy-tests/src/lib.rs | 125 +- packages/strategy-tests/src/operations.rs | 118 +- packages/strategy-tests/src/transitions.rs | 13 +- packages/token-history-contract/.eslintrc | 18 + packages/token-history-contract/.mocharc.yml | 2 + packages/token-history-contract/Cargo.toml | 13 + packages/token-history-contract/LICENSE | 20 + packages/token-history-contract/README.md | 26 + .../token-history-contract/lib/systemIds.js | 4 + packages/token-history-contract/package.json | 29 + .../v1/token-history-contract-documents.json | 580 +++ packages/token-history-contract/src/error.rs | 17 + packages/token-history-contract/src/lib.rs | 37 + packages/token-history-contract/src/v1/mod.rs | 21 + .../token-history-contract/test/.eslintrc | 12 + .../token-history-contract/test/bootstrap.js | 30 + .../test/unit/tokenHistoryContract.spec.js | 451 ++ .../wasm-dpp/src/document/document_facade.rs | 4 +- .../errors/document_already_exists_error.rs | 2 +- .../errors/document_not_provided_error.rs | 2 +- .../errors/invalid_document_action_error.rs | 4 +- packages/wasm-dpp/src/document/factory.rs | 6 +- .../batched_transition/mod.rs | 18 + .../document_create_transition.rs | 2 +- .../document_delete_transition.rs | 0 .../document_replace_transition.rs | 0 .../document_transition/mod.rs | 11 +- .../mod.rs | 53 +- .../batch_transition/token_transition/mod.rs | 18 + .../validation/basic/find_duplicates_by_id.rs | 0 .../basic/find_duplicates_by_indices.rs | 0 .../validation/basic/mod.rs | 0 ...lidate_documents_batch_transition_basic.rs | 0 .../validate_partial_compound_indices.rs | 0 .../validation/mod.rs | 0 .../state/fetch_extended_documents.rs | 0 .../validation/state/mod.rs | 0 ...idate_documents_batch_transitions_state.rs | 0 ...alidate_documents_uniqueness_by_indices.rs | 0 .../src/document/state_transition/mod.rs | 2 +- .../src/errors/consensus/consensus_error.rs | 77 +- .../state_transition/transition_types.rs | 2 +- .../state_transition_factory.rs | 6 +- 919 files changed, 51292 insertions(+), 4825 deletions(-) create mode 100644 packages/rs-dpp/schema/meta_schemas/token/v0/token-meta.json create mode 100644 packages/rs-dpp/src/balances/total_tokens_balance/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/accessors/v1/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs create mode 100644 packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/change_control_rules/authorized_action_takers.rs create mode 100644 packages/rs-dpp/src/data_contract/change_control_rules/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/change_control_rules/v0/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v1/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/group/accessors/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/group/accessors/v0/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/group/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/group/v0/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs delete mode 100644 packages/rs-dpp/src/data_contract/v0/serialization/bincode.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/accessors/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/conversion/cbor.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/conversion/json.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/conversion/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/conversion/value.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/data_contract.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/methods/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/methods/schema.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/mod.rs create mode 100644 packages/rs-dpp/src/data_contract/v1/serialization/mod.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/data_contract/data_contract_token_configuration_update_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/data_contract/invalid_token_base_supply_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_group_positions_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_token_positions_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/group/group_action_not_allowed_on_transition_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/group/mod.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/choosing_token_mint_recipient_not_allowed_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/contract_has_no_tokens_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/destination_identity_for_token_minting_not_set_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/invalid_action_id_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/invalid_group_position_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_id_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_position_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/mod.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/token/token_transfer_to_ourselves_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/group/group_action_already_completed_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/group/group_action_already_signed_by_identity_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/group/group_action_does_not_exist_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/group/identity_not_member_of_group_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/group/mod.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/identity/recipient_identity_does_not_exist_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/token/identity_does_not_have_enough_token_balance_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_frozen_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_not_frozen_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/token/mod.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/token/unauthorized_token_action_error.rs create mode 100644 packages/rs-dpp/src/group/action_event.rs create mode 100644 packages/rs-dpp/src/group/group_action/mod.rs create mode 100644 packages/rs-dpp/src/group/group_action/v0/mod.rs create mode 100644 packages/rs-dpp/src/group/mod.rs create mode 100644 packages/rs-dpp/src/multi_identity_events/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/document_base_transition_trait.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/fields.rs (75%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/from_document.rs (84%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/mod.rs (96%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/v0/from_document.rs (77%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/v0/mod.rs (98%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/v0/v0_methods.rs (94%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_base_transition/v0_methods.rs (87%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/convertible.rs (90%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/from_document.rs (86%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/mod.rs (97%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/v0/from_document.rs (84%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/v0/mod.rs (97%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/v0/v0_methods.rs (76%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_create_transition/v0_methods.rs (80%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_delete_transition/from_document.rs (85%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_delete_transition/mod.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_delete_transition/v0/from_document.rs (69%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_delete_transition/v0/mod.rs (85%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/v0_methods.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_delete_transition/v0_methods.rs (51%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_purchase_transition/from_document.rs (85%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_purchase_transition/mod.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_purchase_transition/v0/from_document.rs (79%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_purchase_transition/v0/mod.rs (90%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_purchase_transition/v0/v0_methods.rs (53%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_purchase_transition/v0_methods.rs (65%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_replace_transition/from_document.rs (79%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_replace_transition/mod.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_replace_transition/v0/from_document.rs (79%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_replace_transition/v0/mod.rs (98%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_replace_transition/v0/v0_methods.rs (68%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_replace_transition/v0_methods.rs (71%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_transfer_transition/from_document.rs (84%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_transfer_transition/mod.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_transfer_transition/v0/from_document.rs (79%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_transfer_transition/v0/mod.rs (92%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_transfer_transition/v0/v0_methods.rs (69%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_transfer_transition/v0_methods.rs (72%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition/mod.rs => batch_transition/batched_transition/document_transition.rs} (74%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition/action_type.rs => batch_transition/batched_transition/document_transition_action_type.rs} (78%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_update_price_transition/from_document.rs (85%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_update_price_transition/mod.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_update_price_transition/v0/from_document.rs (82%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_update_price_transition/v0/mod.rs (99%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_update_price_transition/v0/v0_methods.rs (62%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition/document_transition => batch_transition/batched_transition}/document_update_price_transition/v0_methods.rs (68%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/token_base_transition_accessors.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0_methods.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/fields.rs (93%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/identity_signed.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/json_conversion.rs (52%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/methods/v0/mod.rs (81%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v1/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/state_transition_like.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/cbor_conversion.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/identity_signed.rs (83%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/json_conversion.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/mod.rs (86%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/state_transition_like.rs (72%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/types.rs (53%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/v0_methods.rs (77%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/value_conversion.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/v0/version.rs (52%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/identity_signed.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/json_conversion.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/types.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/value_conversion.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/version.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/validation/find_duplicates_by_id/mod.rs (84%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/validation/find_duplicates_by_id/v0/mod.rs (73%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/validation/mod.rs (100%) rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/validation/validate_basic_structure/mod.rs (88%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs rename packages/rs-dpp/src/state_transition/state_transitions/document/{documents_batch_transition => batch_transition}/value_conversion.rs (61%) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/version.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/mod.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/v0/mod.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/v0_methods.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/identity_signed.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/mod.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/state_transition_like.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/json_conversion.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/value_conversion.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/v0/mod.rs delete mode 100644 packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/version.rs create mode 100644 packages/rs-dpp/src/tokens/allowed_currency.rs create mode 100644 packages/rs-dpp/src/tokens/emergency_action.rs create mode 100644 packages/rs-dpp/src/tokens/errors.rs create mode 100644 packages/rs-dpp/src/tokens/info/methods.rs create mode 100644 packages/rs-dpp/src/tokens/info/mod.rs create mode 100644 packages/rs-dpp/src/tokens/info/v0/mod.rs create mode 100644 packages/rs-dpp/src/tokens/mod.rs create mode 100644 packages/rs-dpp/src/tokens/status/methods.rs create mode 100644 packages/rs-dpp/src/tokens/status/mod.rs create mode 100644 packages/rs-dpp/src/tokens/status/v0/mod.rs create mode 100644 packages/rs-dpp/src/tokens/token_event.rs rename packages/rs-drive-abci/src/execution/platform_events/{block_fee_processing => block_processing_end_events}/add_process_epoch_change_operations/mod.rs (100%) rename packages/rs-drive-abci/src/execution/platform_events/{block_fee_processing => block_processing_end_events}/add_process_epoch_change_operations/v0/mod.rs (100%) rename packages/rs-drive-abci/src/execution/platform_events/{block_fee_processing => block_processing_end_events}/mod.rs (56%) rename packages/rs-drive-abci/src/execution/platform_events/{block_fee_processing/process_block_fees => block_processing_end_events/process_block_fees_and_validate_sum_trees}/mod.rs (79%) rename packages/rs-drive-abci/src/execution/platform_events/{block_fee_processing/process_block_fees => block_processing_end_events/process_block_fees_and_validate_sum_trees}/v0/mod.rs (99%) create mode 100644 packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v1/mod.rs rename packages/rs-drive-abci/src/execution/platform_events/{block_fee_processing => block_processing_end_events}/tests.rs (95%) create mode 100644 packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/common.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v1/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/tokens/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_create_transition_action/mod.rs (83%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_create_transition_action/state_v0/mod.rs (96%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_create_transition_action/state_v1/mod.rs (96%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_create_transition_action/structure_v0/mod.rs (97%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_delete_transition_action/mod.rs (84%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_delete_transition_action/state_v0/mod.rs (92%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_delete_transition_action/structure_v0/mod.rs (91%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_purchase_transition_action/mod.rs (84%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_purchase_transition_action/state_v0/mod.rs (95%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_purchase_transition_action/structure_v0/mod.rs (95%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_replace_transition_action/mod.rs (84%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_replace_transition_action/state_v0/mod.rs (95%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_replace_transition_action/structure_v0/mod.rs (94%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_transfer_transition_action/mod.rs (84%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_transfer_transition_action/state_v0/mod.rs (95%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_transfer_transition_action/structure_v0/mod.rs (94%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_update_price_transition_action/mod.rs (84%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_update_price_transition_action/state_v0/mod.rs (95%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/action_validation/document_update_price_transition_action/structure_v0/mod.rs (94%) create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/structure_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/state_v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/structure_v0/mod.rs rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/advanced_structure/mod.rs (100%) create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/v0/mod.rs rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/balance/mod.rs (76%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/balance/v0/mod.rs (89%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/bindings/data_trigger_binding/mod.rs (89%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/bindings/data_trigger_binding/v0/mod.rs (96%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/bindings/list/mod.rs (79%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/bindings/list/v0/mod.rs (88%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/bindings/mod.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/context.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/executor.rs (58%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/mod.rs (94%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/dashpay/mod.rs (74%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/dashpay/v0/mod.rs (86%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/dpns/mod.rs (70%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/dpns/v0/mod.rs (79%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/feature_flags/mod.rs (70%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/feature_flags/v0/mod.rs (83%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/mod.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/reject/mod.rs (69%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/reject/v0/mod.rs (68%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/withdrawals/mod.rs (74%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/data_triggers/triggers/withdrawals/v0/mod.rs (91%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/identity_contract_nonce/mod.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/identity_contract_nonce/v0/mod.rs (82%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/is_allowed/mod.rs (86%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/is_allowed/v0/mod.rs (75%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/mod.rs (66%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/state/mod.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/state/v0/data_triggers.rs (76%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/state/v0/fetch_contender.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/state/v0/fetch_documents.rs (97%) create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/transformer/mod.rs (100%) rename packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/{documents_batch => batch}/transformer/v0/mod.rs (60%) delete mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs delete mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs delete mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/group_info/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/group_infos/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/group_queries/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identities_token_balances/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identities_token_balances/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identities_token_infos/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identities_token_infos/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identity_token_balances/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identity_token_balances/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identity_token_infos/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/identity_token_infos/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/token_status/v0/mod.rs create mode 100644 packages/rs-drive-abci/tests/strategy_tests/token_tests.rs create mode 100644 packages/rs-drive-abci/tests/supporting_files/contract/basic-token/basic-token.json create mode 100644 packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json create mode 100644 packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs create mode 100644 packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs create mode 100644 packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/mod.rs create mode 100644 packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/estimated_costs/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_group_info/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_group_info/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_group_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/fetch_group_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/mod.rs create mode 100644 packages/rs-drive/src/drive/group/fetch/queries.rs create mode 100644 packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs create mode 100644 packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs create mode 100644 packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/insert/mod.rs create mode 100644 packages/rs-drive/src/drive/group/mod.rs create mode 100644 packages/rs-drive/src/drive/group/paths.rs create mode 100644 packages/rs-drive/src/drive/group/prove/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/initialization/v1/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/add_transaction_history_operations/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/apply_status/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/apply_status/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/queries.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/balance/update.rs create mode 100644 packages/rs-drive/src/drive/tokens/burn/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/burn/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/estimated_costs/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/freeze/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/freeze/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/info/queries.rs create mode 100644 packages/rs-drive/src/drive/tokens/mint/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/mint/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/paths.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/fetch_token_status/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/fetch_token_status/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/prove_token_statuses/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/create_token_trees/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/create_token_trees/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/transfer/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/transfer/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/unfreeze/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/unfreeze/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/batch_transition.rs rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_create_transition.rs (95%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_delete_transition.rs (86%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_purchase_transition.rs (92%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_replace_transition.rs (91%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_transfer_transition.rs (91%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_transition.rs (63%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/document_update_price_transition.rs (90%) rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{ => batch}/document/documents_batch_transition.rs (84%) create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/mod.rs rename packages/rs-drive/src/state_transition_action/action_convert_to_operations/{document => batch}/mod.rs (57%) create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_burn_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_destroy_frozen_funds_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_emergency_action_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_freeze_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_mint_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transfer_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_unfreeze_transition.rs rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_base_transition_action/mod.rs (100%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_base_transition_action/transformer.rs (81%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_base_transition_action/v0/mod.rs (100%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_base_transition_action/v0/transformer.rs (90%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_create_transition_action/mod.rs (98%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_create_transition_action/transformer.rs (86%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_create_transition_action/v0/mod.rs (99%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_create_transition_action/v0/transformer.rs (95%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_delete_transition_action/mod.rs (87%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_delete_transition_action/transformer.rs (78%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_delete_transition_action/v0/mod.rs (89%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_delete_transition_action/v0/transformer.rs (74%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_purchase_transition_action/mod.rs (97%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_purchase_transition_action/transformer.rs (87%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_purchase_transition_action/v0/mod.rs (94%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_purchase_transition_action/v0/transformer.rs (86%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_replace_transition_action/mod.rs (98%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_replace_transition_action/transformer.rs (91%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_replace_transition_action/v0/mod.rs (99%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_replace_transition_action/v0/transformer.rs (88%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_transfer_transition_action/mod.rs (97%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_transfer_transition_action/transformer.rs (87%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_transfer_transition_action/v0/mod.rs (92%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_transfer_transition_action/v0/transformer.rs (85%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch/document_transition/action_type.rs => batch/batched_transition/document_transition/document_transition_action_type.rs} (63%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_update_price_transition_action/mod.rs (97%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_update_price_transition_action/transformer.rs (87%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_update_price_transition_action/v0/mod.rs (93%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/document_update_price_transition_action/v0/transformer.rs (84%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch/batched_transition}/document_transition/mod.rs (51%) create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/v0/transformer.rs rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch}/mod.rs (60%) rename packages/rs-drive/src/state_transition_action/{document/documents_batch => batch}/v0/mod.rs (68%) delete mode 100644 packages/rs-drive/src/state_transition_action/document/mod.rs create mode 100644 packages/rs-drive/src/util/batch/drive_op_batch/group.rs create mode 100644 packages/rs-drive/src/util/batch/drive_op_batch/token.rs create mode 100644 packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/v0/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/v0/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/v0/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_raw_item/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_raw_item/v0/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/v0/mod.rs create mode 100644 packages/rs-drive/tests/supporting_files/contract/tokens/token-example-contract.json create mode 100644 packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v2.rs create mode 100644 packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs create mode 100644 packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs create mode 100644 packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs create mode 100644 packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/v4.rs create mode 100644 packages/rs-platform-version/src/version/v9.rs create mode 100644 packages/search-contract/.eslintrc create mode 100644 packages/search-contract/.mocharc.yml create mode 100644 packages/search-contract/Cargo.toml create mode 100644 packages/search-contract/LICENSE create mode 100644 packages/search-contract/README.md create mode 100644 packages/search-contract/lib/systemIds.js create mode 100644 packages/search-contract/package.json create mode 100644 packages/search-contract/schema/v1/search-contract-documents.json create mode 100644 packages/search-contract/src/error.rs create mode 100644 packages/search-contract/src/lib.rs create mode 100644 packages/search-contract/src/v1/mod.rs create mode 100644 packages/search-contract/test/.eslintrc create mode 100644 packages/search-contract/test/bootstrap.js create mode 100644 packages/search-contract/test/unit/searchContract.spec.js create mode 100644 packages/token-history-contract/.eslintrc create mode 100644 packages/token-history-contract/.mocharc.yml create mode 100644 packages/token-history-contract/Cargo.toml create mode 100644 packages/token-history-contract/LICENSE create mode 100644 packages/token-history-contract/README.md create mode 100644 packages/token-history-contract/lib/systemIds.js create mode 100644 packages/token-history-contract/package.json create mode 100644 packages/token-history-contract/schema/v1/token-history-contract-documents.json create mode 100644 packages/token-history-contract/src/error.rs create mode 100644 packages/token-history-contract/src/lib.rs create mode 100644 packages/token-history-contract/src/v1/mod.rs create mode 100644 packages/token-history-contract/test/.eslintrc create mode 100644 packages/token-history-contract/test/bootstrap.js create mode 100644 packages/token-history-contract/test/unit/tokenHistoryContract.spec.js create mode 100644 packages/wasm-dpp/src/document/state_transition/batch_transition/batched_transition/mod.rs rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/document_transition/document_create_transition.rs (98%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/document_transition/document_delete_transition.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/document_transition/document_replace_transition.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/document_transition/mod.rs (90%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/mod.rs (89%) create mode 100644 packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/basic/find_duplicates_by_id.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/basic/find_duplicates_by_indices.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/basic/mod.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/basic/validate_documents_batch_transition_basic.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/basic/validate_partial_compound_indices.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/mod.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/state/fetch_extended_documents.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/state/mod.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/state/validate_documents_batch_transitions_state.rs (100%) rename packages/wasm-dpp/src/document/state_transition/{document_batch_transition => batch_transition}/validation/state/validate_documents_uniqueness_by_indices.rs (100%) diff --git a/.github/package-filters/js-packages.yml b/.github/package-filters/js-packages.yml index b42237f81b..0c4e0260fa 100644 --- a/.github/package-filters/js-packages.yml +++ b/.github/package-filters/js-packages.yml @@ -2,6 +2,10 @@ - .github/workflows/tests* - packages/wallet-utils-contract/** +'@dashevo/token-history-contract': &token-history-contract + - .github/workflows/tests* + - packages/token-history-contract/** + '@dashevo/dashpay-contract': &dashpay-contract - .github/workflows/tests* - packages/dashpay-contract/** @@ -30,6 +34,7 @@ - *dpns-contract - *withdrawals-contract - *wallet-utils-contract + - *token-history-contract - packages/rs-platform-serialization/** - packages/rs-platform-serialization-derive/** - packages/rs-platform-value/** @@ -80,6 +85,7 @@ dashmate: - *masternode-reward-shares-contract - *dpns-contract - *withdrawals-contract + - *token-history-contract - *wallet-lib - *dapi-client diff --git a/.github/package-filters/rs-packages.yml b/.github/package-filters/rs-packages.yml index c813323e1d..7e31bd9992 100644 --- a/.github/package-filters/rs-packages.yml +++ b/.github/package-filters/rs-packages.yml @@ -2,6 +2,10 @@ wallet-utils-contract: &wallet-utils-contract - .github/workflows/tests* - packages/wallet-utils-contract/** +token-history-contract: &token-history-contract + - .github/workflows/tests* + - packages/token-history-contract/** + dashpay-contract: &dashpay-contract - .github/workflows/tests* - packages/dashpay-contract/** @@ -30,6 +34,7 @@ dpp: &dpp - *dpns-contract - *withdrawals-contract - *wallet-utils-contract + - *token-history-contract - *json-schema-compatibility-validator - packages/rs-platform-serialization/** - packages/rs-platform-serialization-derive/** diff --git a/Cargo.lock b/Cargo.lock index e3f0fe93d7..930e2769ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1318,6 +1318,7 @@ dependencies = [ "platform-version", "serde_json", "thiserror 1.0.64", + "token-history-contract", "wallet-utils-contract", "withdrawals-contract", ] @@ -2097,9 +2098,8 @@ dependencies = [ [[package]] name = "grovedb" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf36cc41af86d8ccb8b7f64fd15006cd83ec979c49cd2ad30628bf855c54d7d" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "axum", "bincode", @@ -2129,9 +2129,8 @@ dependencies = [ [[package]] name = "grovedb-costs" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc526a58bdca58cb86340632081e27264e3557a73608cf29f6738ad9bfab316" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "integer-encoding", "intmap", @@ -2140,9 +2139,8 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd5f01eb50ff57b2c24e856377684d42dacdbd04de7c0189bf2e0e0cd109692" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "grovedb-costs", "hex", @@ -2153,12 +2151,12 @@ dependencies = [ [[package]] name = "grovedb-merk" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce3b133a76e9935f3a57e08598769849d79df582244e1ac99509177e23c2605" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "bincode", "blake3", + "byteorder", "colored", "ed", "grovedb-costs", @@ -2176,15 +2174,16 @@ dependencies = [ [[package]] name = "grovedb-path" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67dc8bc00b9be473f7b25670d1422daadd706c9b09ed6aa5cf2caf8722a487ac" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +dependencies = [ + "hex", +] [[package]] name = "grovedb-storage" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905cff776de89b9ee1e96979861e254b0912170b35d89678ad782f487a22a2e3" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "blake3", "grovedb-costs", @@ -2202,9 +2201,8 @@ dependencies = [ [[package]] name = "grovedb-version" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a987e051c8c9cf8fa381b29b243d4951f8c1f24f9c90ceed52afca3ac460986c" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "thiserror 2.0.11", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2212,9 +2210,8 @@ dependencies = [ [[package]] name = "grovedb-visualize" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56eee6f57d324505611de0042af2b6b9933235e704a1a6542ff7ba5b5c56f64e" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "hex", "itertools 0.14.0", @@ -2222,9 +2219,8 @@ dependencies = [ [[package]] name = "grovedbg-types" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cfa37a90579ba2c71e074d6047c1dcfc19caa458fbcefd4e8e31a02f6a9fe38" +version = "3.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" dependencies = [ "serde", "serde_with 3.9.0", @@ -5042,6 +5038,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "token-history-contract" +version = "1.6.2" +dependencies = [ + "platform-value", + "platform-version", + "serde_json", + "thiserror 1.0.64", +] + [[package]] name = "tokio" version = "1.40.0" diff --git a/Cargo.toml b/Cargo.toml index 02295b6b47..b8444e3bd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ members = [ "packages/rs-json-schema-compatibility-validator", "packages/check-features", "packages/wallet-utils-contract", + "packages/token-history-contract" ] [workspace.package] diff --git a/Dockerfile b/Dockerfile index 0050ed916a..709ea2b5b2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -353,6 +353,7 @@ COPY --parents \ packages/feature-flags-contract \ packages/dpns-contract \ packages/wallet-utils-contract \ + packages/token-history-contract \ packages/data-contracts \ packages/strategy-tests \ packages/simple-signer \ @@ -419,6 +420,7 @@ COPY --parents \ packages/rs-drive-abci \ packages/dashpay-contract \ packages/wallet-utils-contract \ + packages/token-history-contract \ packages/withdrawals-contract \ packages/masternode-reward-shares-contract \ packages/feature-flags-contract \ @@ -508,6 +510,7 @@ COPY --parents \ packages/dashpay-contract \ packages/withdrawals-contract \ packages/wallet-utils-contract \ + packages/token-history-contract \ packages/masternode-reward-shares-contract \ packages/feature-flags-contract \ packages/dpns-contract \ @@ -628,6 +631,7 @@ COPY --from=build-dashmate-helper /platform/packages/js-grpc-common packages/js- COPY --from=build-dashmate-helper /platform/packages/dapi-grpc packages/dapi-grpc COPY --from=build-dashmate-helper /platform/packages/dash-spv packages/dash-spv COPY --from=build-dashmate-helper /platform/packages/wallet-utils-contract packages/wallet-utils-contract +COPY --from=build-dashmate-helper /platform/packages/token-history-contract packages/token-history-contract COPY --from=build-dashmate-helper /platform/packages/withdrawals-contract packages/withdrawals-contract COPY --from=build-dashmate-helper /platform/packages/masternode-reward-shares-contract packages/masternode-reward-shares-contract COPY --from=build-dashmate-helper /platform/packages/feature-flags-contract packages/feature-flags-contract diff --git a/package.json b/package.json index 4e8f3efa73..958f8f9793 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "test:dashpay-contract": "ultra -r --filter \"packages/@(dashpay-contract|js-dash-sdk|js-drive|js-dapi-client|wasm-dpp|wallet-lib|dapi|platform-test-suite)\" test", "test:dpns-contract": "ultra -r --filter \"packages/@(dpns-contract|js-dash-sdk|js-drive|js-dapi-client|wasm-dpp|wallet-lib|dapi|platform-test-suite)\" test", "test:feature-flags-contract": "ultra -r --filter \"packages/@(feature-flags-contract|js-dash-sdk|js-drive|js-dapi-client|wasm-dpp|wallet-lib|dapi|platform-test-suite)\" test", + "test:token-history-contract": "ultra -r --filter \"packages/@(token-history-contract|js-dash-sdk|js-drive|js-dapi-client|wasm-dpp|wallet-lib|dapi|platform-test-suite)\" test", "test:dapi-client": "ultra -r --filter \"packages/@(js-dapi-client|wallet-lib|js-dash-sdk|platform-test-suite)\" test", "test:sdk": "ultra -r --filter \"packages/@(js-dash-sdk|platform-test-suite)\" test", "test:spv": "ultra -r --filter \"packages/@(dash-spv|js-dapi-client)\" test", @@ -65,7 +66,8 @@ "packages/masternode-reward-shares-contract", "packages/dash-spv", "packages/wasm-dpp", - "packages/withdrawals-contract" + "packages/withdrawals-contract", + "packages/token-history-contract" ], "resolutions": { "elliptic": "6.5.7", diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs index 642b614ab9..49b9c29032 100644 --- a/packages/dapi-grpc/build.rs +++ b/packages/dapi-grpc/build.rs @@ -47,7 +47,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // Derive features for versioned messages // // "GetConsensusParamsRequest" is excluded as this message does not support proofs - const VERSIONED_REQUESTS: [&str; 30] = [ + const VERSIONED_REQUESTS: [&str; 34] = [ "GetDataContractHistoryRequest", "GetDataContractRequest", "GetDataContractsRequest", @@ -78,6 +78,10 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetEvonodesProposedEpochBlocksByIdsRequest", "GetEvonodesProposedEpochBlocksByRangeRequest", "GetStatusRequest", + "GetIdentityTokenBalancesRequest", + "GetIdentitiesTokenBalancesRequest", + "GetIdentityTokenInfosRequest", + "GetIdentitiesTokenInfosRequest", ]; // The following responses are excluded as they don't support proofs: @@ -85,7 +89,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // - "GetStatusResponse" // // "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests - const VERSIONED_RESPONSES: [&str; 29] = [ + const VERSIONED_RESPONSES: [&str; 33] = [ "GetDataContractHistoryResponse", "GetDataContractResponse", "GetDataContractsResponse", @@ -115,6 +119,10 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetVotePollsByEndDateResponse", "GetTotalCreditsInPlatformResponse", "GetEvonodesProposedEpochBlocksResponse", + "GetIdentityTokenBalancesResponse", + "GetIdentitiesTokenBalancesResponse", + "GetIdentityTokenInfosResponse", + "GetIdentitiesTokenInfosResponse", ]; check_unique(&VERSIONED_REQUESTS).expect("VERSIONED_REQUESTS"); diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index b46d784ceb..81da114443 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -55,6 +55,14 @@ service Platform { rpc getPathElements(GetPathElementsRequest) returns (GetPathElementsResponse); rpc getStatus(GetStatusRequest) returns (GetStatusResponse); rpc getCurrentQuorumsInfo(GetCurrentQuorumsInfoRequest) returns (GetCurrentQuorumsInfoResponse); + rpc getIdentityTokenBalances(GetIdentityTokenBalancesRequest) returns (GetIdentityTokenBalancesResponse); + rpc getIdentitiesTokenBalances(GetIdentitiesTokenBalancesRequest) returns (GetIdentitiesTokenBalancesResponse); + rpc getIdentityTokenInfos(GetIdentityTokenInfosRequest) returns (GetIdentityTokenInfosResponse); + rpc getIdentitiesTokenInfos(GetIdentitiesTokenInfosRequest) returns (GetIdentitiesTokenInfosResponse); + rpc getTokenStatuses(GetTokenStatusesRequest) returns (GetTokenStatusesResponse); + rpc getGroupInfo(GetGroupInfoRequest) returns (GetGroupInfoResponse); +// rpc getActiveGroupActions(GetActiveGroupActionsRequest) returns (GetActiveGroupActionsResponse); +// rpc getClosedGroupActions(GetClosedGroupActionsRequest) returns (GetClosedGroupActionsResponse); } // Proof message includes cryptographic proofs for validating responses @@ -1215,3 +1223,360 @@ message GetCurrentQuorumsInfoResponse { } oneof version { GetCurrentQuorumsInfoResponseV0 v0 = 1; } } + +message GetIdentityTokenBalancesRequest { + message GetIdentityTokenBalancesRequestV0 { + bytes identity_id = 1; // ID of the identity + repeated bytes token_ids = 2; // List of token IDs + bool prove = 3; // Flag to request a proof as the response + } + oneof version { + GetIdentityTokenBalancesRequestV0 v0 = 1; + } +} + +message GetIdentityTokenBalancesResponse { + message GetIdentityTokenBalancesResponseV0 { + message TokenBalanceEntry { + bytes token_id = 1; // Token ID + optional uint64 balance = 2; // Token balance for the contract + } + + message TokenBalances { + repeated TokenBalanceEntry token_balances = 1; // List of token balances + } + + oneof result { + TokenBalances token_balances = 1; // Actual token balances + Proof proof = 2; // Proof of the token balances, if requested + } + ResponseMetadata metadata = 3; // Metadata about the blockchain state + } + oneof version { + GetIdentityTokenBalancesResponseV0 v0 = 1; + } +} + +message GetIdentitiesTokenBalancesRequest { + message GetIdentitiesTokenBalancesRequestV0 { + bytes token_id = 1; // Token ID + repeated bytes identity_ids = 2; // List of identity IDs + bool prove = 3; // Flag to request a proof as the response + } + oneof version { + GetIdentitiesTokenBalancesRequestV0 v0 = 1; + } +} + +message GetIdentitiesTokenBalancesResponse { + message GetIdentitiesTokenBalancesResponseV0 { + message IdentityTokenBalanceEntry { + bytes identity_id = 1; // Identity ID + optional uint64 balance = 2; // Token balance for the identity + } + + message IdentityTokenBalances { + repeated IdentityTokenBalanceEntry identity_token_balances = 1; // List of identity token balances + } + + oneof result { + IdentityTokenBalances identity_token_balances = 1; // Actual identity token balances + Proof proof = 2; // Proof of the balances, if requested + } + ResponseMetadata metadata = 3; // Metadata about the blockchain state + } + oneof version { + GetIdentitiesTokenBalancesResponseV0 v0 = 1; + } +} + + + +message GetIdentityTokenInfosRequest { + message GetIdentityTokenInfosRequestV0 { + bytes identity_id = 1; + repeated bytes token_ids = 2; + bool prove = 3; + } + oneof version { + GetIdentityTokenInfosRequestV0 v0 = 1; + } +} + +message GetIdentityTokenInfosResponse { + message GetIdentityTokenInfosResponseV0 { + message TokenIdentityInfoEntry { + bool frozen = 1; + } + + message TokenInfoEntry { + bytes token_id = 1; + optional TokenIdentityInfoEntry info = 2; + } + + message TokenInfos { + repeated TokenInfoEntry token_infos = 1; + } + + oneof result { + TokenInfos token_infos = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { + GetIdentityTokenInfosResponseV0 v0 = 1; + } +} + +message GetIdentitiesTokenInfosRequest { + message GetIdentitiesTokenInfosRequestV0 { + bytes token_id = 1; + repeated bytes identity_ids = 2; + bool prove = 3; + } + oneof version { + GetIdentitiesTokenInfosRequestV0 v0 = 1; + } +} + +message GetIdentitiesTokenInfosResponse { + message GetIdentitiesTokenInfosResponseV0 { + message TokenIdentityInfoEntry { + bool frozen = 1; + } + + message TokenInfoEntry { + bytes identity_id = 1; + optional TokenIdentityInfoEntry info = 2; + } + + message IdentityTokenInfos { + repeated TokenInfoEntry token_infos = 1; + } + + oneof result { + IdentityTokenInfos identity_token_infos = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { + GetIdentitiesTokenInfosResponseV0 v0 = 1; + } +} + +message GetTokenStatusesRequest { + message GetTokenStatusesRequestV0 { + repeated bytes token_ids = 1; + bool prove = 2; + } + oneof version { + GetTokenStatusesRequestV0 v0 = 1; + } +} + +message GetTokenStatusesResponse { + message GetTokenStatusesResponseV0 { + message TokenStatusEntry { + bytes token_id = 1; + optional bool paused = 2; + } + + message TokenStatuses { + repeated TokenStatusEntry token_statuses = 1; + } + + oneof result { + TokenStatuses token_statuses = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { + GetTokenStatusesResponseV0 v0 = 1; + } +} + +message GetGroupInfoRequest { + message GetGroupInfoRequestV0 { + bytes contract_id = 1; + uint32 group_contract_position = 2; + bool prove = 3; + } + oneof version { + GetGroupInfoRequestV0 v0 = 1; + } +} + +message GetGroupInfoResponse { + message GetGroupInfoResponseV0 { + message GroupMemberEntry { + bytes member_id = 1; + uint32 power = 2; + } + + message GroupInfoEntry { + repeated GroupMemberEntry members = 1; + uint32 group_required_power = 2; + } + + message GroupInfo { + optional GroupInfoEntry group_info = 1; + } + + oneof result { + GroupInfo group_info = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 4; + } + oneof version { + GetGroupInfoResponseV0 v0 = 1; + } +} + +message GetGroupInfosRequest { + message StartAtGroupContractPosition { + uint32 start_group_contract_position = 1; + bool start_group_contract_position_included = 2; + } + + message GetGroupInfosRequestV0 { + bytes contract_id = 1; + optional StartAtGroupContractPosition start_at_group_contract_position = 2; + optional uint32 count = 3; + bool prove = 4; + } + oneof version { + GetGroupInfosRequestV0 v0 = 1; + } +} + +message GetGroupInfosResponse { + message GetGroupInfosResponseV0 { + message GroupMemberEntry { + bytes member_id = 1; + uint32 power = 2; + } + + message GroupPositionInfoEntry { + uint32 group_contract_position = 1; + repeated GroupMemberEntry members = 2; + uint32 group_required_power = 3; + } + + message GroupInfos { + repeated GroupPositionInfoEntry group_infos = 1; + } + + oneof result { + GroupInfos group_infos = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 4; + } + oneof version { + GetGroupInfosResponseV0 v0 = 1; + } +} + +message GetActiveGroupActionsRequest { + message GetActiveGroupActionsRequestV0 { + bytes contract_id = 1; + uint32 group_contract_position = 2; + bool prove = 3; + } + oneof version { + GetActiveGroupActionsRequestV0 v0 = 1; + } +} + +message GetActiveGroupActionsResponse { + message GetActiveGroupActionsResponseV0 { + // Mint event + message MintEvent { + uint64 amount = 1; // Amount to mint + bytes recipient_id = 2; // Recipient identifier + string public_note = 3; // Public note + } + + // Burn event + message BurnEvent { + uint64 amount = 1; // Amount to burn + string public_note = 2; // Public note + } + + // Freeze event + message FreezeEvent { + bytes frozen_id = 1; // Identifier of the frozen entity + string public_note = 2; // Public note + } + + // Unfreeze event + message UnfreezeEvent { + bytes frozen_id = 1; // Identifier of the unfrozen entity + string public_note = 2; // Public note + } + + // Destroy frozen funds event + message DestroyFrozenFundsEvent { + bytes frozen_id = 1; // Identifier of the frozen entity + uint64 amount = 2; // Amount to destroy + string public_note = 3; // Public note + } + + // Transfer event + message TransferEvent { + bytes recipient_id = 1; // Recipient identifier + string public_note = 2; // Public note + bytes shared_encrypted_note = 3; // Shared encrypted note + bytes personal_encrypted_note = 4; // Personal encrypted note + uint64 amount = 5; // Amount transferred + } + + // Emergency action event + message EmergencyActionEvent { + string action_type = 1; // Emergency action type + string public_note = 2; // Public note + } + + // Event associated with this action + message GroupActionEvent { + oneof event_type { + TokenEvent token_event = 1; // Token event details + } + } + + // Details for token events + message TokenEvent { + oneof type { + MintEvent mint = 1; // Mint event details + BurnEvent burn = 2; // Burn event details + FreezeEvent freeze = 3; // Freeze event details + UnfreezeEvent unfreeze = 4; // Unfreeze event details + DestroyFrozenFundsEvent destroy_frozen_funds = 5; // Destroy frozen funds + TransferEvent transfer = 6; // Transfer event details + EmergencyActionEvent emergency_action = 7; // Emergency action details + } + } + + message GroupActionEntry { + bytes action_id = 1; // Unique identifier for the action + GroupActionEvent event = 2; // The event data + } + + message GroupActions { + repeated GroupActionEntry group_actions = 1; + } + + oneof result { + GroupActions group_actions = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { + GetActiveGroupActionsResponseV0 v0 = 1; + } +} \ No newline at end of file diff --git a/packages/data-contracts/Cargo.toml b/packages/data-contracts/Cargo.toml index e9ad5401a6..4008b43aee 100644 --- a/packages/data-contracts/Cargo.toml +++ b/packages/data-contracts/Cargo.toml @@ -17,3 +17,4 @@ dashpay-contract = { path = "../dashpay-contract" } feature-flags-contract = { path = "../feature-flags-contract" } platform-value = { path = "../rs-platform-value" } wallet-utils-contract = { path = "../wallet-utils-contract" } +token-history-contract = { path = "../token-history-contract" } diff --git a/packages/data-contracts/src/error.rs b/packages/data-contracts/src/error.rs index 0550873b01..7c0c802b71 100644 --- a/packages/data-contracts/src/error.rs +++ b/packages/data-contracts/src/error.rs @@ -119,3 +119,20 @@ impl From for Error { } } } + +impl From for Error { + fn from(e: token_history_contract::Error) -> Self { + match e { + token_history_contract::Error::UnknownVersionMismatch { + method, + known_versions, + received, + } => Error::UnknownVersionMismatch { + method, + known_versions, + received, + }, + token_history_contract::Error::InvalidSchemaJson(e) => Error::InvalidSchemaJson(e), + } + } +} diff --git a/packages/data-contracts/src/lib.rs b/packages/data-contracts/src/lib.rs index 65f324137f..a78ffefc37 100644 --- a/packages/data-contracts/src/lib.rs +++ b/packages/data-contracts/src/lib.rs @@ -9,6 +9,7 @@ pub use feature_flags_contract; pub use masternode_reward_shares_contract; use platform_value::Identifier; use platform_version::version::PlatformVersion; +pub use token_history_contract; pub use wallet_utils_contract; pub use withdrawals_contract; @@ -21,6 +22,7 @@ pub enum SystemDataContract { DPNS = 3, Dashpay = 4, WalletUtils = 5, + TokenHistory = 6, } pub struct DataContractSource { @@ -40,6 +42,7 @@ impl SystemDataContract { SystemDataContract::DPNS => dpns_contract::ID_BYTES, SystemDataContract::Dashpay => dashpay_contract::ID_BYTES, SystemDataContract::WalletUtils => wallet_utils_contract::ID_BYTES, + SystemDataContract::TokenHistory => token_history_contract::ID_BYTES, }; Identifier::new(bytes) } @@ -92,6 +95,13 @@ impl SystemDataContract { definitions: wallet_utils_contract::load_definitions(platform_version)?, document_schemas: wallet_utils_contract::load_documents_schemas(platform_version)?, }, + SystemDataContract::TokenHistory => DataContractSource { + id_bytes: token_history_contract::ID_BYTES, + owner_id_bytes: token_history_contract::OWNER_ID_BYTES, + version: platform_version.system_data_contracts.wallet as u32, + definitions: token_history_contract::load_definitions(platform_version)?, + document_schemas: token_history_contract::load_documents_schemas(platform_version)?, + }, }; Ok(data) diff --git a/packages/rs-dpp/schema/meta_schemas/token/v0/token-meta.json b/packages/rs-dpp/schema/meta_schemas/token/v0/token-meta.json new file mode 100644 index 0000000000..7e5d833fc8 --- /dev/null +++ b/packages/rs-dpp/schema/meta_schemas/token/v0/token-meta.json @@ -0,0 +1,245 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json", + "type": "object", + "$defs": { + "localization": { + "type": "string", + "pattern": "^[\\p{L}\\p{N}]*$", + "minLength": 1, + "maxLength": 64, + "$comment": "Allow only alphanumeric characters" + }, + "identifier": { + "type": "string", + "contentMediaType": "application/x.dash.dpp.identifier", + "byteArray": true, + "minLength": 32, + "maxLength": 32, + "description": "A 32-byte identifier" + }, + "optionalIdentifier": { + "type": ["string", "null"], + "contentMediaType": "application/x.dash.dpp.identifier", + "byteArray": true, + "minLength": 32, + "maxLength": 32, + "description": "A 32-byte identifier" + }, + "authorizedActionTakers": { + "description": "Specifies who is authorized to take certain actions", + "oneOf": [ + { + "type": "object", + "properties": { + "type": { "const": "noOne" } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { "const": "contractOwner" } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { "const": "mainGroup" } + }, + "required": ["type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "type": { "const": "specifiedIdentities" }, + "identifiers": { + "type": "array", + "description": "An array of authorized identifiers", + "items": { + "$ref": "#/$defs/identifier" + }, + "uniqueItems": true + }, + "requiredSignersCount": { + "$ref": "#/$defs/requiredSignersCount", + "description": "Rules for required signers within these specified identities" + } + }, + "required": ["type", "identifiers", "requiredSignersCount"], + "additionalProperties": false + } + ] + }, + "changeControlRules": { + "type": "object", + "description": "Defines who can make changes to certain parameters and who can change that ability", + "properties": { + "authorizedToMakeChange": { + "$ref": "#/$defs/authorizedActionTakers", + "description": "Who is authorized to make the relevant change" + }, + "authorizedToChangeAuthorizedActionTakers": { + "$ref": "#/$defs/authorizedActionTakers", + "description": "Who is authorized to modify the list of people who can make the change" + }, + "changingAuthorizedActionTakersToNoOneAllowed": { + "type": "boolean", + "description": "Whether it is allowed to change the authorized action takers to no one in the future" + }, + "changingAuthorizedActionTakersToContractOwnerAllowed": { + "type": "boolean", + "description": "Whether it is allowed to change the authorized action takers to contract owner in the future" + } + }, + "required": [ + "authorizedToMakeChange", + "authorizedToChangeAuthorizedActionTakers", + "changingAuthorizedActionTakersToNoOneAllowed", + "changingAuthorizedActionTakersToContractOwnerAllowed" + ], + "additionalProperties": false + }, + "requiredSignersCount": { + "type": "integer", + "description": "How many signers are required to authorize actions", + "minimum": 1, + "maximum": 255 + } + }, + "properties": { + "description": { + "type": "string", + "maxLength": 1024, + "description": "Token description" + }, + "displayConventions": { + "type": "object", + "description": "Token display conventions including capitalization and localization", + "properties": { + "capitalize": { + "type": "boolean", + "description": "Indicates whether token names should be capitalized" + }, + "localizations": { + "type": "object", + "description": "A map of locale keys to their corresponding singular/plural forms", + "additionalProperties": { + "type": "object", + "description": "Localization forms for a given locale key", + "properties": { + "singularForm": { + "$ref": "#/$defs/localization" + }, + "pluralForm": { + "$ref": "#/$defs/localization" + } + }, + "required": [ + "singularForm", + "pluralForm" + ], + "additionalProperties": false + }, + "maxProperties": 255, + "minProperties": 1, + "propertyNames": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + }, + "decimals": { + "type": "integer", + "minimum": 0, + "description": "The number of decimal places the token supports" + } + }, + "required": ["capitalize", "localizations", "decimals"], + "additionalProperties": false + }, + "initialSupply": { + "type": "integer", + "minimum": 0, + "description": "The initial (base) supply of the token at creation time" + }, + "initialSupplyDestinationIdentityId": { + "$ref": "#/$defs/optionalIdentifier", + "description": "Optional identity where initial supply tokens are sent. If not set, the data contract owner identity is used" + }, + "maxSupply": { + "type": ["integer", "null"], + "minimum": 1, + "description": "The maximum supply the token can ever have, or null if there is no maximum" + }, + "maxSupplyChangeRules": { + "$ref": "#/$defs/changeControlRules", + "description": "Rules governing who can change the max supply and under what conditions" + }, + "mintedTokensDestinationIdentityId": { + "$ref": "#/$defs/optionalIdentifier", + "description": "Optional identity where newly minted tokens are sent. If set then minted tokens can be sent only to this identity" + }, + "mintedTokensDestinationIdentityRules": { + "$ref": "#/$defs/changeControlRules", + "description": "Rules for changing the new tokens destination identity" + }, + "mintingRules": { + "$ref": "#/$defs/changeControlRules", + "description": "Rules governing who and how new tokens can be minted manually" + }, + "burningRules": { + "$ref": "#/$defs/changeControlRules", + "description": "Rules governing who and how tokens can be burned manually" + }, + "mainControlGroup": { + "type": "array", + "description": "The main control group, if present", + "items": { + "type": "object", + "properties": { + "identifiers": { + "type": "array", + "description": "A set of identities representing members of the control group", + "items": { + "$ref": "#/$defs/identifier" + }, + "uniqueItems": true + }, + "requiredSignersCount": { + "$ref": "#/$defs/requiredSignersCount" + } + }, + "required": ["identifiers", "requiredSignersCount"], + "additionalProperties": false + } + }, + "mainControlGroupCanBeModified": { + "$ref": "#/$defs/authorizedActionTakers", + "description": "Specifies which entities are authorized to modify the main control group" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string", + "maxLength": 255 + }, + "additionalProperties": { + "type": "string", + "maxLength": 1024 + }, + "minProperties": 1, + "maxProperties": 255, + "description": "Token arbitrary metadata" + } + }, + "required": [ + "displayConventions", + "initialSupply" + ], + "additionalProperties": false +} diff --git a/packages/rs-dpp/src/balances/credits.rs b/packages/rs-dpp/src/balances/credits.rs index d0f9e2805b..4376686a96 100644 --- a/packages/rs-dpp/src/balances/credits.rs +++ b/packages/rs-dpp/src/balances/credits.rs @@ -19,6 +19,12 @@ pub type Duffs = u64; pub type Credits = u64; +/// Token Amount type +pub type TokenAmount = u64; + +/// Sum token amount +pub type SumTokenAmount = i128; + /// Signed Credits type is used for internal computations and total credits /// balance verification diff --git a/packages/rs-dpp/src/balances/mod.rs b/packages/rs-dpp/src/balances/mod.rs index a6b4881120..c0f505ac78 100644 --- a/packages/rs-dpp/src/balances/mod.rs +++ b/packages/rs-dpp/src/balances/mod.rs @@ -1,3 +1,4 @@ pub mod total_credits_balance; pub mod credits; +pub mod total_tokens_balance; diff --git a/packages/rs-dpp/src/balances/total_tokens_balance/mod.rs b/packages/rs-dpp/src/balances/total_tokens_balance/mod.rs new file mode 100644 index 0000000000..84aa157643 --- /dev/null +++ b/packages/rs-dpp/src/balances/total_tokens_balance/mod.rs @@ -0,0 +1,53 @@ +use crate::balances::credits::SumTokenAmount; +use crate::ProtocolError; +use std::fmt; + +/// The outcome of verifying token balances +#[derive(Copy, Clone, Debug)] +pub struct TotalTokensBalance { + /// all the tokens in platform + pub total_tokens_in_platform: SumTokenAmount, + /// all the tokens in identity token balances + pub total_identity_token_balances: SumTokenAmount, +} + +impl fmt::Display for TotalTokensBalance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "TotalTokensBalance {{")?; + writeln!( + f, + " total_tokens_in_platform: {},", + self.total_tokens_in_platform + )?; + writeln!( + f, + " total_identity_token_balances: {}", + self.total_identity_token_balances + )?; + write!(f, "}}") + } +} +impl TotalTokensBalance { + /// Is the outcome okay? basically do the values match up + /// Errors in case of overflow + pub fn ok(&self) -> Result { + let TotalTokensBalance { + total_tokens_in_platform, + total_identity_token_balances, + } = *self; + + if total_tokens_in_platform < 0 { + return Err(ProtocolError::CriticalCorruptedCreditsCodeExecution( + "Tokens in platform are less than 0".to_string(), + )); + } + + if total_identity_token_balances < 0 { + return Err(ProtocolError::CriticalCorruptedCreditsCodeExecution( + "Tokens in identity balances are less than 0".to_string(), + )); + } + + Ok(total_tokens_in_platform == total_identity_token_balances) + } +} diff --git a/packages/rs-dpp/src/data_contract/accessors/mod.rs b/packages/rs-dpp/src/data_contract/accessors/mod.rs index fc5dc0789b..92fdb99bd9 100644 --- a/packages/rs-dpp/src/data_contract/accessors/mod.rs +++ b/packages/rs-dpp/src/data_contract/accessors/mod.rs @@ -1,45 +1,58 @@ use crate::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; use crate::data_contract::config::DataContractConfig; use crate::data_contract::document_type::{DocumentType, DocumentTypeRef}; -use crate::data_contract::DocumentName; +use crate::data_contract::{ + DocumentName, GroupContractPosition, TokenContractPosition, EMPTY_GROUPS, EMPTY_TOKENS, +}; use crate::metadata::Metadata; use crate::prelude::DataContract; use platform_value::Identifier; +use crate::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; use crate::data_contract::errors::DataContractError; +use crate::data_contract::group::Group; +use crate::tokens::errors::TokenError; +use crate::ProtocolError; use std::collections::BTreeMap; pub mod v0; +pub mod v1; impl DataContractV0Getters for DataContract { fn id(&self) -> Identifier { match self { DataContract::V0(v0) => v0.id(), + DataContract::V1(v1) => v1.id(), } } fn id_ref(&self) -> &Identifier { match self { DataContract::V0(v0) => v0.id_ref(), + DataContract::V1(v1) => v1.id_ref(), } } fn version(&self) -> u32 { match self { DataContract::V0(v0) => v0.version(), + DataContract::V1(v1) => v1.version(), } } fn owner_id(&self) -> Identifier { match self { DataContract::V0(v0) => v0.owner_id(), + DataContract::V1(v1) => v1.owner_id(), } } fn document_type_cloned_for_name(&self, name: &str) -> Result { match self { DataContract::V0(v0) => v0.document_type_cloned_for_name(name), + DataContract::V1(v1) => v1.document_type_cloned_for_name(name), } } @@ -49,72 +62,84 @@ impl DataContractV0Getters for DataContract { ) -> Result<&DocumentType, DataContractError> { match self { DataContract::V0(v0) => v0.document_type_borrowed_for_name(name), + DataContract::V1(v1) => v1.document_type_borrowed_for_name(name), } } fn document_type_for_name(&self, name: &str) -> Result { match self { DataContract::V0(v0) => v0.document_type_for_name(name), + DataContract::V1(v1) => v1.document_type_for_name(name), } } fn document_type_optional_for_name(&self, name: &str) -> Option { match self { DataContract::V0(v0) => v0.document_type_optional_for_name(name), + DataContract::V1(v1) => v1.document_type_optional_for_name(name), } } fn document_type_cloned_optional_for_name(&self, name: &str) -> Option { match self { DataContract::V0(v0) => v0.document_type_cloned_optional_for_name(name), + DataContract::V1(v1) => v1.document_type_cloned_optional_for_name(name), } } fn has_document_type_for_name(&self, name: &str) -> bool { match self { DataContract::V0(v0) => v0.has_document_type_for_name(name), + DataContract::V1(v1) => v1.has_document_type_for_name(name), } } fn document_types_with_contested_indexes(&self) -> BTreeMap<&DocumentName, &DocumentType> { match self { DataContract::V0(v0) => v0.document_types_with_contested_indexes(), + DataContract::V1(v1) => v1.document_types_with_contested_indexes(), } } fn document_types(&self) -> &BTreeMap { match self { DataContract::V0(v0) => v0.document_types(), + DataContract::V1(v1) => v1.document_types(), } } fn document_types_mut(&mut self) -> &mut BTreeMap { match self { DataContract::V0(v0) => v0.document_types_mut(), + DataContract::V1(v1) => v1.document_types_mut(), } } fn metadata(&self) -> Option<&Metadata> { match self { DataContract::V0(v0) => v0.metadata(), + DataContract::V1(v1) => v1.metadata(), } } fn metadata_mut(&mut self) -> Option<&mut Metadata> { match self { DataContract::V0(v0) => v0.metadata_mut(), + DataContract::V1(v1) => v1.metadata_mut(), } } fn config(&self) -> &DataContractConfig { match self { DataContract::V0(v0) => v0.config(), + DataContract::V1(v1) => v1.config(), } } fn config_mut(&mut self) -> &mut DataContractConfig { match self { DataContract::V0(v0) => v0.config_mut(), + DataContract::V1(v1) => v1.config_mut(), } } } @@ -123,36 +148,185 @@ impl DataContractV0Setters for DataContract { fn set_id(&mut self, id: Identifier) { match self { DataContract::V0(v0) => v0.set_id(id), + DataContract::V1(v1) => v1.set_id(id), } } fn set_version(&mut self, version: u32) { match self { DataContract::V0(v0) => v0.set_version(version), + DataContract::V1(v1) => v1.set_version(version), } } fn increment_version(&mut self) { match self { DataContract::V0(v0) => v0.increment_version(), + DataContract::V1(v1) => v1.increment_version(), } } fn set_owner_id(&mut self, owner_id: Identifier) { match self { DataContract::V0(v0) => v0.set_owner_id(owner_id), + DataContract::V1(v1) => v1.set_owner_id(owner_id), } } fn set_metadata(&mut self, metadata: Option) { match self { DataContract::V0(v0) => v0.set_metadata(metadata), + DataContract::V1(v1) => v1.set_metadata(metadata), } } fn set_config(&mut self, config: DataContractConfig) { match self { DataContract::V0(v0) => v0.set_config(config), + DataContract::V1(v1) => v1.set_config(config), + } + } +} + +/// Implementing DataContractV1Getters for DataContract +impl DataContractV1Getters for DataContract { + /// Returns a reference to the groups map. + fn group(&self, position: GroupContractPosition) -> Result<&Group, ProtocolError> { + match self { + DataContract::V0(_) => Err(ProtocolError::GroupNotFound( + "There can not be a group in v0 data contracts".to_string(), + )), + DataContract::V1(v1) => v1.group(position), + } + } + + /// Returns a reference to the groups map. + fn groups(&self) -> &BTreeMap { + match self { + DataContract::V0(_) => &EMPTY_GROUPS, + DataContract::V1(v1) => &v1.groups, + } + } + + /// Returns a mutable reference to the groups map. + /// Returns `None` for V0 since it doesn't have groups. + fn groups_mut(&mut self) -> Option<&mut BTreeMap> { + match self { + DataContract::V0(_) => None, + DataContract::V1(v1) => Some(&mut v1.groups), + } + } + + /// Returns a reference to a group or an error. + /// Returns an Error for V0 since it doesn't have groups. + fn expected_group(&self, position: GroupContractPosition) -> Result<&Group, ProtocolError> { + match self { + DataContract::V0(_) => Err(ProtocolError::GroupNotFound( + "Group not found in contract V0".to_string(), + )), + DataContract::V1(v1) => { + v1.groups + .get(&position) + .ok_or(ProtocolError::GroupNotFound(format!( + "Group not found at position {} in contract {}", + position, + self.id() + ))) + } + } + } + + /// Returns a reference to the tokens map. + fn tokens(&self) -> &BTreeMap { + match self { + DataContract::V0(_) => &EMPTY_TOKENS, + DataContract::V1(v1) => &v1.tokens, + } + } + + /// Returns a mutable reference to the tokens map. + /// Returns `None` for V0 since it doesn't have tokens. + fn tokens_mut(&mut self) -> Option<&mut BTreeMap> { + match self { + DataContract::V0(_) => None, + DataContract::V1(v1) => Some(&mut v1.tokens), + } + } + + /// Returns a mutable reference to a token configuration or an error. + /// Returns an Error for V0 since it doesn't have tokens. + fn expected_token_configuration( + &self, + position: TokenContractPosition, + ) -> Result<&TokenConfiguration, ProtocolError> { + match self { + DataContract::V0(_) => Err(ProtocolError::Token( + TokenError::TokenNotFoundOnContractVersion.into(), + )), + DataContract::V1(v1) => v1.tokens.get(&position).ok_or(ProtocolError::Token( + TokenError::TokenNotFoundAtPositionError.into(), + )), + } + } + + /// Returns a mutable reference to a token configuration + /// Returns `None` for V0 since it doesn't have tokens. + fn token_configuration_mut( + &mut self, + position: TokenContractPosition, + ) -> Option<&mut TokenConfiguration> { + match self { + DataContract::V0(_) => None, + DataContract::V1(v1) => v1.tokens.get_mut(&position), + } + } + + fn token_id(&self, position: TokenContractPosition) -> Option { + match self { + DataContract::V0(_) => None, + DataContract::V1(v1) => v1.token_id(position), + } + } +} + +impl DataContractV1Setters for DataContract { + /// Sets the groups map for the data contract. + fn set_groups(&mut self, groups: BTreeMap) { + match self { + DataContract::V0(_) => {} + DataContract::V1(v1) => { + v1.groups = groups; + } + } + } + + /// Sets the tokens map for the data contract. + fn set_tokens(&mut self, tokens: BTreeMap) { + match self { + DataContract::V0(_) => {} + DataContract::V1(v1) => { + v1.tokens = tokens; + } + } + } + + /// Adds or updates a single group in the groups map. + fn add_group(&mut self, position: GroupContractPosition, group: Group) { + match self { + DataContract::V0(_) => {} + DataContract::V1(v1) => { + v1.groups.insert(position, group); + } + } + } + + /// Adds or updates a single token configuration in the tokens map. + fn add_token(&mut self, id: TokenContractPosition, token: TokenConfiguration) { + match self { + DataContract::V0(_) => {} + DataContract::V1(v1) => { + v1.tokens.insert(id, token); + } } } } diff --git a/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs b/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs new file mode 100644 index 0000000000..0727a24a21 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/accessors/v1/mod.rs @@ -0,0 +1,57 @@ +use crate::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::group::Group; +use crate::data_contract::{GroupContractPosition, TokenContractPosition}; +use crate::ProtocolError; +use platform_value::Identifier; +use std::collections::BTreeMap; + +pub trait DataContractV1Getters: DataContractV0Getters { + /// Gets a group at a certain position + fn group(&self, position: GroupContractPosition) -> Result<&Group, ProtocolError>; + /// Returns a reference to the groups map. + fn groups(&self) -> &BTreeMap; + + /// Returns a mutable reference to the groups map. + fn groups_mut(&mut self) -> Option<&mut BTreeMap>; + /// Returns a reference to a group or an error. + /// Returns an Error for V0 since it doesn't have groups. + fn expected_group(&self, position: GroupContractPosition) -> Result<&Group, ProtocolError>; + + /// Returns a reference to the tokens map. + fn tokens(&self) -> &BTreeMap; + + /// Returns a mutable reference to the tokens map. + fn tokens_mut(&mut self) -> Option<&mut BTreeMap>; + + /// Returns a mutable reference to a token configuration or an error. + /// Returns an Error for V0 since it doesn't have tokens. + fn expected_token_configuration( + &self, + position: TokenContractPosition, + ) -> Result<&TokenConfiguration, ProtocolError>; + + /// Returns a mutable reference to a token configuration + /// Returns `None` for V0 since it doesn't have tokens. + fn token_configuration_mut( + &mut self, + position: TokenContractPosition, + ) -> Option<&mut TokenConfiguration>; + + /// Returns the token id at a certain position + fn token_id(&self, position: TokenContractPosition) -> Option; +} + +pub trait DataContractV1Setters: DataContractV0Setters { + /// Sets the groups map for the data contract. + fn set_groups(&mut self, groups: BTreeMap); + + /// Sets the tokens map for the data contract. + fn set_tokens(&mut self, tokens: BTreeMap); + + /// Adds or updates a single group in the groups map. + fn add_group(&mut self, pos: GroupContractPosition, group: Group); + + /// Adds or updates a single token configuration in the tokens map. + fn add_token(&mut self, pos: TokenContractPosition, token: TokenConfiguration); +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/mod.rs new file mode 100644 index 0000000000..ad9156e391 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/mod.rs @@ -0,0 +1 @@ +pub mod token_configuration; 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 new file mode 100644 index 0000000000..46c82e7995 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/mod.rs @@ -0,0 +1,255 @@ +pub mod v0; + +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::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +use crate::data_contract::change_control_rules::ChangeControlRules; +use crate::data_contract::GroupContractPosition; +use platform_value::Identifier; + +/// Implementing TokenConfigurationV0Getters for TokenConfiguration +impl TokenConfigurationV0Getters for TokenConfiguration { + /// Returns a reference to the conventions. + fn conventions(&self) -> &TokenConfigurationConventionV0 { + match self { + TokenConfiguration::V0(v0) => v0.conventions(), + } + } + + /// Returns a mutable reference to the conventions. + fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0 { + match self { + TokenConfiguration::V0(v0) => v0.conventions_mut(), + } + } + + /// Returns the base supply. + fn base_supply(&self) -> u64 { + match self { + TokenConfiguration::V0(v0) => v0.base_supply(), + } + } + + /// Returns if we keep history. + fn keeps_history(&self) -> bool { + match self { + TokenConfiguration::V0(v0) => v0.keeps_history(), + } + } + + /// Returns if we start as paused. + fn start_as_paused(&self) -> bool { + match self { + TokenConfiguration::V0(v0) => v0.start_as_paused(), + } + } + + /// Returns the maximum supply. + fn max_supply(&self) -> Option { + match self { + TokenConfiguration::V0(v0) => v0.max_supply(), + } + } + + /// Returns the max supply change rules. + fn max_supply_change_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.max_supply_change_rules(), + } + } + + /// Returns the new tokens destination identity. + fn new_tokens_destination_identity(&self) -> Option { + match self { + TokenConfiguration::V0(v0) => v0.new_tokens_destination_identity(), + } + } + + /// Returns the new tokens destination identity rules. + fn new_tokens_destination_identity_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.new_tokens_destination_identity_rules(), + } + } + /// Returns whether minting allows choosing a destination. + fn minting_allow_choosing_destination(&self) -> bool { + match self { + TokenConfiguration::V0(v0) => v0.minting_allow_choosing_destination(), + } + } + + /// Returns the rules for minting destination selection. + fn minting_allow_choosing_destination_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.minting_allow_choosing_destination_rules(), + } + } + + /// Returns the manual minting rules. + fn manual_minting_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.manual_minting_rules(), + } + } + + /// Returns the manual burning rules. + fn manual_burning_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.manual_burning_rules(), + } + } + + /// Returns the freeze rules. + fn freeze_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.freeze_rules(), + } + } + + /// Returns the unfreeze rules. + fn unfreeze_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.unfreeze_rules(), + } + } + + fn destroy_frozen_funds_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.destroy_frozen_funds_rules(), + } + } + + fn emergency_action_rules(&self) -> &ChangeControlRules { + match self { + TokenConfiguration::V0(v0) => v0.emergency_action_rules(), + } + } + + /// Returns the main control group. + fn main_control_group(&self) -> Option { + match self { + TokenConfiguration::V0(v0) => v0.main_control_group(), + } + } + + /// Returns the main control group can be modified. + fn main_control_group_can_be_modified(&self) -> &AuthorizedActionTakers { + match self { + TokenConfiguration::V0(v0) => v0.main_control_group_can_be_modified(), + } + } +} + +/// Implementing TokenConfigurationV0Setters for TokenConfiguration +impl TokenConfigurationV0Setters for TokenConfiguration { + /// Sets the conventions. + fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0) { + match self { + TokenConfiguration::V0(v0) => v0.set_conventions(conventions), + } + } + + /// Sets the base supply. + fn set_base_supply(&mut self, base_supply: u64) { + match self { + TokenConfiguration::V0(v0) => v0.set_base_supply(base_supply), + } + } + + /// Sets the maximum supply. + fn set_max_supply(&mut self, max_supply: Option) { + match self { + TokenConfiguration::V0(v0) => v0.set_max_supply(max_supply), + } + } + + /// Sets the max supply change rules. + fn set_max_supply_change_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_max_supply_change_rules(rules), + } + } + + /// Sets the new tokens destination identity. + fn set_new_tokens_destination_identity(&mut self, id: Option) { + match self { + TokenConfiguration::V0(v0) => v0.set_new_tokens_destination_identity(id), + } + } + + /// Sets the new tokens destination identity rules. + fn set_new_tokens_destination_identity_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_new_tokens_destination_identity_rules(rules), + } + } + + /// Sets the manual minting rules. + fn set_manual_minting_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_manual_minting_rules(rules), + } + } + + /// Sets the manual burning rules. + fn set_manual_burning_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_manual_burning_rules(rules), + } + } + + /// Sets the freeze rules. + fn set_freeze_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_freeze_rules(rules), + } + } + + /// Sets the unfreeze rules. + fn set_unfreeze_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_unfreeze_rules(rules), + } + } + + fn set_destroy_frozen_funds_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_destroy_frozen_funds_rules(rules), + } + } + + fn set_emergency_action_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_emergency_action_rules(rules), + } + } + + /// Sets the main control group. + fn set_main_control_group(&mut self, group: Option) { + match self { + TokenConfiguration::V0(v0) => v0.set_main_control_group(group), + } + } + + /// Sets the main control group can be modified. + fn set_main_control_group_can_be_modified(&mut self, action_takers: AuthorizedActionTakers) { + match self { + TokenConfiguration::V0(v0) => v0.set_main_control_group_can_be_modified(action_takers), + } + } + + fn set_minting_allow_choosing_destination(&mut self, value: bool) { + match self { + TokenConfiguration::V0(v0) => v0.set_minting_allow_choosing_destination(value), + } + } + + fn set_minting_allow_choosing_destination_rules(&mut self, rules: ChangeControlRules) { + match self { + TokenConfiguration::V0(v0) => v0.set_minting_allow_choosing_destination_rules(rules), + } + } +} 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 new file mode 100644 index 0000000000..83fde97a8e --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/accessors/v0/mod.rs @@ -0,0 +1,105 @@ +use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationConventionV0; +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; + +/// Accessor trait for getters of `TokenConfigurationV0` +pub trait TokenConfigurationV0Getters { + /// Returns a reference to the conventions. + fn conventions(&self) -> &TokenConfigurationConventionV0; + + /// Returns a mutable reference to the conventions. + fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0; + + /// Returns the base supply. + fn base_supply(&self) -> u64; + /// Returns the base supply. + fn keeps_history(&self) -> bool; + fn start_as_paused(&self) -> bool; + + /// Returns the maximum supply. + fn max_supply(&self) -> Option; + + /// Returns the max supply change rules. + fn max_supply_change_rules(&self) -> &ChangeControlRules; + + /// Returns the new tokens destination identity. + fn new_tokens_destination_identity(&self) -> Option; + + /// Returns the new tokens destination identity rules. + fn new_tokens_destination_identity_rules(&self) -> &ChangeControlRules; + /// Returns whether minting allows choosing a destination. + fn minting_allow_choosing_destination(&self) -> bool; + /// Returns the rules for minting destination selection. + fn minting_allow_choosing_destination_rules(&self) -> &ChangeControlRules; + + /// Returns the manual minting rules. + fn manual_minting_rules(&self) -> &ChangeControlRules; + + /// Returns the manual burning rules. + fn manual_burning_rules(&self) -> &ChangeControlRules; + + /// Returns the freeze rules. + fn freeze_rules(&self) -> &ChangeControlRules; + + /// Returns the unfreeze rules. + fn unfreeze_rules(&self) -> &ChangeControlRules; + /// Returns the destroy frozen funds rules. + fn destroy_frozen_funds_rules(&self) -> &ChangeControlRules; + /// Returns the emergency action rules. + fn emergency_action_rules(&self) -> &ChangeControlRules; + + /// Returns the main control group. + fn main_control_group(&self) -> Option; + + /// Returns the main control group can be modified. + fn main_control_group_can_be_modified(&self) -> &AuthorizedActionTakers; +} + +/// Accessor trait for setters of `TokenConfigurationV0` +pub trait TokenConfigurationV0Setters { + /// Sets the conventions. + fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0); + + /// Sets the base supply. + fn set_base_supply(&mut self, base_supply: u64); + + /// Sets the maximum supply. + fn set_max_supply(&mut self, max_supply: Option); + + /// Sets the max supply change rules. + fn set_max_supply_change_rules(&mut self, rules: ChangeControlRules); + + /// Sets the new tokens destination identity. + fn set_new_tokens_destination_identity(&mut self, id: Option); + + /// Sets the new tokens destination identity rules. + fn set_new_tokens_destination_identity_rules(&mut self, rules: ChangeControlRules); + + /// Sets the manual minting rules. + fn set_manual_minting_rules(&mut self, rules: ChangeControlRules); + + /// Sets the manual burning rules. + fn set_manual_burning_rules(&mut self, rules: ChangeControlRules); + + /// Sets the freeze rules. + fn set_freeze_rules(&mut self, rules: ChangeControlRules); + + /// Sets the unfreeze rules. + fn set_unfreeze_rules(&mut self, rules: ChangeControlRules); + /// Sets the `destroy frozen funds` rules. + fn set_destroy_frozen_funds_rules(&mut self, rules: ChangeControlRules); + /// Sets the emergency action rules. + fn set_emergency_action_rules(&mut self, rules: ChangeControlRules); + + /// Sets the main control group. + fn set_main_control_group(&mut self, group: Option); + + /// Sets the main control group can be modified. + fn set_main_control_group_can_be_modified(&mut self, action_takers: AuthorizedActionTakers); + /// Sets whether minting allows choosing a destination. + fn set_minting_allow_choosing_destination(&mut self, value: bool); + /// Sets the rules for minting destination selection. + fn set_minting_allow_choosing_destination_rules(&mut self, rules: ChangeControlRules); +} 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 new file mode 100644 index 0000000000..5e5a7181a5 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/mod.rs @@ -0,0 +1 @@ +mod validate_token_configuration_update; 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 new file mode 100644 index 0000000000..9dda53c984 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/mod.rs @@ -0,0 +1,43 @@ +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::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_value::Identifier; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +mod v0; + +impl TokenConfiguration { + pub fn validate_token_config_update( + &self, + new_config: &TokenConfiguration, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .validation + .data_contract + .validate_token_config_update + { + 0 => Ok(self.validate_token_config_update_v0( + new_config, + contract_owner_id, + main_group, + groups, + action_taker, + )), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "validate_token_config_update".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_update/v0/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs new file mode 100644 index 0000000000..a11f775a57 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/methods/validate_token_configuration_update/v0/mod.rs @@ -0,0 +1,283 @@ +use crate::consensus::basic::data_contract::DataContractTokenConfigurationUpdateError; +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::validation::SimpleConsensusValidationResult; +use platform_value::Identifier; +use std::collections::BTreeMap; + +impl TokenConfiguration { + #[inline(always)] + pub(super) fn validate_token_config_update_v0( + &self, + new_config: &TokenConfiguration, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + ) -> 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(), + ); + } + + // Check immutable fields: base_supply + if old.base_supply != new.base_supply { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "baseSupply".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + + // Check changes to max_supply and max_supply_change_rules + if old.max_supply != new.max_supply + || old.max_supply_change_rules != new.max_supply_change_rules + { + if !old.max_supply_change_rules.can_change_to( + &new.max_supply_change_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "maxSupply or maxSupplyChangeRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to new_tokens_destination_identity and rules + if old.new_tokens_destination_identity != new.new_tokens_destination_identity + || old.new_tokens_destination_identity_rules + != new.new_tokens_destination_identity_rules + { + if !old.new_tokens_destination_identity_rules.can_change_to( + &new.new_tokens_destination_identity_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "newTokensDestinationIdentity or newTokensDestinationIdentityRules" + .to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to minting_allow_choosing_destination and its rules + if old.minting_allow_choosing_destination != new.minting_allow_choosing_destination + || old.minting_allow_choosing_destination_rules + != new.minting_allow_choosing_destination_rules + { + if !old.minting_allow_choosing_destination_rules.can_change_to( + &new.minting_allow_choosing_destination_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "mintingAllowChoosingDestination or mintingAllowChoosingDestinationRules" + .to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to manual_minting_rules + if old.manual_minting_rules != new.manual_minting_rules { + if !old.manual_minting_rules.can_change_to( + &new.manual_minting_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "manualMintingRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to manual_burning_rules + if old.manual_burning_rules != new.manual_burning_rules { + if !old.manual_burning_rules.can_change_to( + &new.manual_burning_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "manualBurningRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to freeze_rules + if old.freeze_rules != new.freeze_rules { + if !old.freeze_rules.can_change_to( + &new.freeze_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "freezeRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to unfreeze_rules + if old.unfreeze_rules != new.unfreeze_rules { + if !old.unfreeze_rules.can_change_to( + &new.unfreeze_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "unfreezeRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to destroy_frozen_funds_rules + if old.destroy_frozen_funds_rules != new.destroy_frozen_funds_rules { + if !old.destroy_frozen_funds_rules.can_change_to( + &new.destroy_frozen_funds_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "destroyFrozenFundsRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to emergency_action_rules + if old.emergency_action_rules != new.emergency_action_rules { + if !old.emergency_action_rules.can_change_to( + &new.emergency_action_rules, + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "emergencyActionRules".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to main_control_group + 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) + { + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "mainControlGroup".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + } + + // Check changes to main_control_group_can_be_modified + if old.main_control_group_can_be_modified != new.main_control_group_can_be_modified { + // Assuming this is immutable + return SimpleConsensusValidationResult::new_with_error( + DataContractTokenConfigurationUpdateError::new( + "update".to_string(), + "mainControlGroupCanBeModified".to_string(), + self.clone(), + new_config.clone(), + ) + .into(), + ); + } + + // If we reach here with no errors, return an empty result + SimpleConsensusValidationResult::new() + } +} diff --git a/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs new file mode 100644 index 0000000000..e5e34c6664 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/mod.rs @@ -0,0 +1,33 @@ +use crate::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; +use bincode::{Decode, Encode}; +use derive_more::From; +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; +use std::fmt; + +pub mod accessors; +mod methods; +pub mod v0; + +#[derive(Serialize, Deserialize, Encode, Decode, Debug, Clone, PartialEq, Eq, From)] +#[serde(tag = "$format_version")] +pub enum TokenConfiguration { + #[serde(rename = "0")] + V0(TokenConfigurationV0), +} + +impl TokenConfiguration { + pub fn as_cow_v0(&self) -> Cow { + match self { + TokenConfiguration::V0(v0) => Cow::Borrowed(v0), + } + } +} + +impl fmt::Display for TokenConfiguration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TokenConfiguration::V0(v0) => write!(f, "{}", v0), + } + } +} 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 new file mode 100644 index 0000000000..d0115ead55 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/accessors.rs @@ -0,0 +1,191 @@ +use crate::data_contract::associated_token::token_configuration::accessors::v0::{ + TokenConfigurationV0Getters, TokenConfigurationV0Setters, +}; +use crate::data_contract::associated_token::token_configuration::v0::{ + TokenConfigurationConventionV0, 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; + +/// Implementing `TokenConfigurationV0Getters` for `TokenConfigurationV0` +impl TokenConfigurationV0Getters for TokenConfigurationV0 { + /// Returns a reference to the conventions. + fn conventions(&self) -> &TokenConfigurationConventionV0 { + &self.conventions + } + + /// Returns a mutable reference to the conventions. + fn conventions_mut(&mut self) -> &mut TokenConfigurationConventionV0 { + &mut self.conventions + } + + /// Returns the base supply. + fn base_supply(&self) -> u64 { + self.base_supply + } + + /// Returns if we keep history. + fn keeps_history(&self) -> bool { + self.keeps_history + } + + /// Returns if we start off as paused + fn start_as_paused(&self) -> bool { + self.start_as_paused + } + + /// Returns the maximum supply. + fn max_supply(&self) -> Option { + self.max_supply + } + + /// Returns the max supply change rules. + fn max_supply_change_rules(&self) -> &ChangeControlRules { + &self.max_supply_change_rules + } + + /// Returns the new tokens destination identity. + fn new_tokens_destination_identity(&self) -> Option { + self.new_tokens_destination_identity + } + + /// Returns the new tokens destination identity rules. + fn new_tokens_destination_identity_rules(&self) -> &ChangeControlRules { + &self.new_tokens_destination_identity_rules + } + + /// Returns whether minting allows choosing a destination. + fn minting_allow_choosing_destination(&self) -> bool { + self.minting_allow_choosing_destination + } + + /// Returns the rules for minting destination selection. + fn minting_allow_choosing_destination_rules(&self) -> &ChangeControlRules { + &self.minting_allow_choosing_destination_rules + } + + /// Returns the manual minting rules. + fn manual_minting_rules(&self) -> &ChangeControlRules { + &self.manual_minting_rules + } + + /// Returns the manual burning rules. + fn manual_burning_rules(&self) -> &ChangeControlRules { + &self.manual_burning_rules + } + + /// Returns the freeze rules. + fn freeze_rules(&self) -> &ChangeControlRules { + &self.freeze_rules + } + + /// Returns the unfreeze rules. + fn unfreeze_rules(&self) -> &ChangeControlRules { + &self.unfreeze_rules + } + + /// Returns the `destroy frozen funds` rules. + fn destroy_frozen_funds_rules(&self) -> &ChangeControlRules { + &self.destroy_frozen_funds_rules + } + + /// Returns the emergency action rules. + fn emergency_action_rules(&self) -> &ChangeControlRules { + &self.emergency_action_rules + } + + /// Returns the main control group. + fn main_control_group(&self) -> Option { + self.main_control_group + } + + /// Returns the main control group can be modified. + fn main_control_group_can_be_modified(&self) -> &AuthorizedActionTakers { + &self.main_control_group_can_be_modified + } +} + +/// Implementing `TokenConfigurationV0Setters` for `TokenConfigurationV0` +impl TokenConfigurationV0Setters for TokenConfigurationV0 { + /// Sets the conventions. + fn set_conventions(&mut self, conventions: TokenConfigurationConventionV0) { + self.conventions = conventions; + } + + /// Sets the base supply. + fn set_base_supply(&mut self, base_supply: u64) { + self.base_supply = base_supply; + } + + /// Sets the maximum supply. + fn set_max_supply(&mut self, max_supply: Option) { + self.max_supply = max_supply; + } + + /// Sets the max supply change rules. + fn set_max_supply_change_rules(&mut self, rules: ChangeControlRules) { + self.max_supply_change_rules = rules; + } + + /// Sets the new tokens destination identity. + fn set_new_tokens_destination_identity(&mut self, id: Option) { + self.new_tokens_destination_identity = id; + } + + /// Sets the new tokens destination identity rules. + fn set_new_tokens_destination_identity_rules(&mut self, rules: ChangeControlRules) { + self.new_tokens_destination_identity_rules = rules; + } + + /// Sets the manual minting rules. + fn set_manual_minting_rules(&mut self, rules: ChangeControlRules) { + self.manual_minting_rules = rules; + } + + /// Sets the manual burning rules. + fn set_manual_burning_rules(&mut self, rules: ChangeControlRules) { + self.manual_burning_rules = rules; + } + + /// Sets the freeze rules. + fn set_freeze_rules(&mut self, rules: ChangeControlRules) { + self.freeze_rules = rules; + } + + /// Sets the unfreeze rules. + fn set_unfreeze_rules(&mut self, rules: ChangeControlRules) { + self.unfreeze_rules = rules; + } + + /// Sets the destroy frozen funds rules. + fn set_destroy_frozen_funds_rules(&mut self, rules: ChangeControlRules) { + self.destroy_frozen_funds_rules = rules; + } + + /// Sets the emergency action rules. + fn set_emergency_action_rules(&mut self, rules: ChangeControlRules) { + self.emergency_action_rules = rules; + } + + /// Sets the main control group. + fn set_main_control_group(&mut self, group: Option) { + self.main_control_group = group; + } + + /// Sets the main control group can be modified. + fn set_main_control_group_can_be_modified(&mut self, action_takers: AuthorizedActionTakers) { + self.main_control_group_can_be_modified = action_takers; + } + + /// Sets whether minting allows choosing a destination. + fn set_minting_allow_choosing_destination(&mut self, value: bool) { + self.minting_allow_choosing_destination = value; + } + + /// Sets the rules for minting destination selection. + fn set_minting_allow_choosing_destination_rules(&mut self, rules: ChangeControlRules) { + self.minting_allow_choosing_destination_rules = rules; + } +} 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 new file mode 100644 index 0000000000..4aed4bdc11 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/associated_token/token_configuration/v0/mod.rs @@ -0,0 +1,220 @@ +mod accessors; + +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; +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, + /// The supply at the creation of the token + pub base_supply: u64, + /// The maximum supply the token can ever have + #[serde(default)] + pub max_supply: Option, + /// Do we keep history, default is true. + #[serde(default = "default_keeps_history")] + pub keeps_history: bool, + /// Do we start off as paused, meaning that we can not transfer till we unpause. + #[serde(default = "default_starts_as_paused")] + pub start_as_paused: bool, + /// Who can change the max supply + /// Even if set no one can ever change this under the base supply + #[serde(default = "default_change_control_rules")] + pub max_supply_change_rules: ChangeControlRules, + #[serde(default)] + pub new_tokens_destination_identity: Option, + #[serde(default = "default_change_control_rules")] + pub new_tokens_destination_identity_rules: ChangeControlRules, + #[serde(default = "default_minting_allow_choosing_destination")] + pub minting_allow_choosing_destination: bool, + #[serde(default = "default_change_control_rules")] + pub minting_allow_choosing_destination_rules: ChangeControlRules, + #[serde(default = "default_contract_owner_change_control_rules")] + pub manual_minting_rules: ChangeControlRules, + #[serde(default = "default_contract_owner_change_control_rules")] + pub manual_burning_rules: ChangeControlRules, + #[serde(default = "default_change_control_rules")] + pub freeze_rules: ChangeControlRules, + #[serde(default = "default_change_control_rules")] + pub unfreeze_rules: ChangeControlRules, + #[serde(default = "default_change_control_rules")] + pub destroy_frozen_funds_rules: ChangeControlRules, + #[serde(default = "default_change_control_rules")] + pub emergency_action_rules: ChangeControlRules, + #[serde(default)] + pub main_control_group: Option, + #[serde(default)] + pub main_control_group_can_be_modified: AuthorizedActionTakers, +} + +// Default function for `minting_allow_choosing_destination` to return `true` +fn default_minting_allow_choosing_destination() -> bool { + true +} + +// Default function for `keeps_history` +fn default_keeps_history() -> bool { + true // Default to `true` for keeps_history +} + +// Default function for `starts_as_paused` +fn default_starts_as_paused() -> bool { + false +} + +fn default_change_control_rules() -> ChangeControlRules { + ChangeControlRules::V0(ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_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, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }) +} + +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}}", + self.conventions, + self.base_supply, + self.max_supply, + self.keeps_history, + self.start_as_paused, + self.max_supply_change_rules, + self.new_tokens_destination_identity, + self.new_tokens_destination_identity_rules, + self.minting_allow_choosing_destination, + self.minting_allow_choosing_destination_rules, + self.manual_minting_rules, + self.manual_burning_rules, + self.freeze_rules, + self.unfreeze_rules, + self.destroy_frozen_funds_rules, + self.emergency_action_rules, + self.main_control_group, + self.main_control_group_can_be_modified + ) + } +} + +impl TokenConfigurationV0 { + pub fn default_most_restrictive() -> Self { + Self { + conventions: TokenConfigurationConventionV0 { + localizations: Default::default(), + decimals: 8, + }, + 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, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_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, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_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, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + manual_minting_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + manual_burning_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + freeze_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + unfreeze_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + destroy_frozen_funds_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + emergency_action_rules: ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + } + .into(), + main_control_group: None, + main_control_group_can_be_modified: AuthorizedActionTakers::NoOne, + } + } +} 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 new file mode 100644 index 0000000000..7a23c4259d --- /dev/null +++ b/packages/rs-dpp/src/data_contract/change_control_rules/authorized_action_takers.rs @@ -0,0 +1,80 @@ +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 bincode::{Decode, Encode}; +use platform_value::Identifier; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, Default)] +pub enum AuthorizedActionTakers { + #[default] + NoOne, + ContractOwner, + MainGroup, + Group(GroupContractPosition), +} + +impl AuthorizedActionTakers { + pub fn allowed_for_action_taker( + &self, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + ) -> bool { + match self { + // No one is allowed + AuthorizedActionTakers::NoOne => false, + + // Only the contract owner is allowed + AuthorizedActionTakers::ContractOwner => match action_taker { + ActionTaker::SingleIdentity(action_taker) => action_taker == contract_owner_id, + ActionTaker::SpecifiedIdentities(action_takers) => { + action_takers.contains(contract_owner_id) + } + }, + + // 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) + } else { + false + } + } + + // 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) + } else { + false + } + } + } + } + + /// Helper method to check if action takers meet the group's required power threshold. + fn is_action_taker_authorized(group: &Group, action_taker: &ActionTaker) -> bool { + match action_taker { + ActionTaker::SingleIdentity(member_id) => { + let power = group.members().get(member_id).cloned().unwrap_or_default(); + power >= group.required_power() + } + ActionTaker::SpecifiedIdentities(action_takers) => { + // Calculate the total power of action takers who are members of the group + let total_power: GroupMemberPower = group + .members() + .iter() + .filter(|(member_id, _)| action_takers.contains(*member_id)) + .map(|(_, power)| *power) + .sum(); + + // Compare total power to the group's required power + total_power >= group.required_power() as GroupMemberPower + } + } + } +} 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 new file mode 100644 index 0000000000..2385e11435 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/change_control_rules/mod.rs @@ -0,0 +1,57 @@ +pub mod authorized_action_takers; +pub mod v0; + +use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +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 bincode::{Decode, Encode}; +use derive_more::From; +use platform_value::Identifier; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, From)] +pub enum ChangeControlRules { + V0(ChangeControlRulesV0), +} + +impl ChangeControlRules { + pub fn authorized_to_make_change_action_takers(&self) -> &AuthorizedActionTakers { + match self { + ChangeControlRules::V0(v0) => &v0.authorized_to_make_change, + } + } + pub fn can_make_change( + &self, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + ) -> bool { + match self { + ChangeControlRules::V0(v0) => { + v0.can_make_change(contract_owner_id, main_group, groups, action_taker) + } + } + } + pub fn can_change_to( + &self, + other: &ChangeControlRules, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + ) -> bool { + match (self, other) { + (ChangeControlRules::V0(v0), ChangeControlRules::V0(v0_other)) => v0.can_change_to( + v0_other, + contract_owner_id, + main_group, + groups, + action_taker, + ), + } + } +} 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 new file mode 100644 index 0000000000..41261680ce --- /dev/null +++ b/packages/rs-dpp/src/data_contract/change_control_rules/v0/mod.rs @@ -0,0 +1,115 @@ +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 bincode::{Decode, Encode}; +use platform_value::Identifier; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Serialize, Deserialize, Decode, Encode, Debug, Clone, PartialEq, Eq, Default)] +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, + /// 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, +} + +impl ChangeControlRulesV0 { + pub fn can_make_change( + &self, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + ) -> bool { + self.authorized_to_make_change.allowed_for_action_taker( + contract_owner_id, + main_group, + groups, + action_taker, + ) + } + pub fn can_change_to( + &self, + other: &ChangeControlRulesV0, + contract_owner_id: &Identifier, + main_group: Option<&Group>, + groups: &BTreeMap, + action_taker: &ActionTaker, + ) -> 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( + contract_owner_id, + main_group, + groups, + action_taker, + ) { + return false; + } + + // Check if authorized_to_make_change is being modified + 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) + { + return false; + } + + // If we are changing to NoOne, ensure it's allowed + if let AuthorizedActionTakers::NoOne = other.authorized_to_make_change { + if !self.changing_authorized_action_takers_to_no_one_allowed { + 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) + { + 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; + } + } + + // 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 { + return false; + } + } + } + + // If we reach here, the changes are allowed + true + } +} diff --git a/packages/rs-dpp/src/data_contract/conversion/cbor/mod.rs b/packages/rs-dpp/src/data_contract/conversion/cbor/mod.rs index 541fabd5ba..8683b2dbb4 100644 --- a/packages/rs-dpp/src/data_contract/conversion/cbor/mod.rs +++ b/packages/rs-dpp/src/data_contract/conversion/cbor/mod.rs @@ -1,6 +1,7 @@ mod v0; use crate::data_contract::v0::DataContractV0; +use crate::data_contract::v1::DataContractV1; use crate::prelude::DataContract; use crate::util::cbor_value::CborCanonicalMap; use crate::version::PlatformVersion; @@ -27,9 +28,16 @@ impl DataContractCborConversionMethodsV0 for DataContract { platform_version, )? .into()), + 1 => Ok(DataContractV1::from_cbor_with_id( + cbor_bytes, + contract_id, + full_validation, + platform_version, + )? + .into()), version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::from_cbor_with_id".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } @@ -48,9 +56,12 @@ impl DataContractCborConversionMethodsV0 for DataContract { 0 => Ok( DataContractV0::from_cbor(cbor_bytes, full_validation, platform_version)?.into(), ), + 1 => Ok( + DataContractV1::from_cbor(cbor_bytes, full_validation, platform_version)?.into(), + ), version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::from_cbor".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } @@ -59,6 +70,7 @@ impl DataContractCborConversionMethodsV0 for DataContract { fn to_cbor(&self, platform_version: &PlatformVersion) -> Result, ProtocolError> { match self { DataContract::V0(v0) => v0.to_cbor(platform_version), + DataContract::V1(v1) => v1.to_cbor(platform_version), } } diff --git a/packages/rs-dpp/src/data_contract/conversion/json/mod.rs b/packages/rs-dpp/src/data_contract/conversion/json/mod.rs index b06f6ff2ff..2e4147653c 100644 --- a/packages/rs-dpp/src/data_contract/conversion/json/mod.rs +++ b/packages/rs-dpp/src/data_contract/conversion/json/mod.rs @@ -2,7 +2,7 @@ mod v0; pub use v0::*; use crate::data_contract::v0::DataContractV0; -use crate::data_contract::DataContract; +use crate::data_contract::{DataContract, DataContractV1}; use crate::version::PlatformVersion; use crate::ProtocolError; use serde_json::Value as JsonValue; @@ -24,9 +24,12 @@ impl DataContractJsonConversionMethodsV0 for DataContract { 0 => Ok( DataContractV0::from_json(json_value, full_validation, platform_version)?.into(), ), + 1 => Ok( + DataContractV1::from_json(json_value, full_validation, platform_version)?.into(), + ), version => Err(ProtocolError::UnknownVersionMismatch { - method: "DataContract::from_json_object".to_string(), - known_versions: vec![0], + method: "DataContract::from_json".to_string(), + known_versions: vec![0, 1], received: version, }), } @@ -35,6 +38,7 @@ impl DataContractJsonConversionMethodsV0 for DataContract { fn to_json(&self, platform_version: &PlatformVersion) -> Result { match self { DataContract::V0(v0) => v0.to_json(platform_version), + DataContract::V1(v1) => v1.to_json(platform_version), } } @@ -44,6 +48,7 @@ impl DataContractJsonConversionMethodsV0 for DataContract { ) -> Result { match self { DataContract::V0(v0) => v0.to_validating_json(platform_version), + DataContract::V1(v1) => v1.to_validating_json(platform_version), } } } diff --git a/packages/rs-dpp/src/data_contract/conversion/value/mod.rs b/packages/rs-dpp/src/data_contract/conversion/value/mod.rs index bc54e6e80a..59d07245ca 100644 --- a/packages/rs-dpp/src/data_contract/conversion/value/mod.rs +++ b/packages/rs-dpp/src/data_contract/conversion/value/mod.rs @@ -2,6 +2,7 @@ pub mod v0; use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; use crate::data_contract::v0::DataContractV0; +use crate::data_contract::v1::DataContractV1; use crate::data_contract::DataContract; use crate::version::PlatformVersion; use crate::ProtocolError; @@ -21,9 +22,12 @@ impl DataContractValueConversionMethodsV0 for DataContract { 0 => Ok( DataContractV0::from_value(raw_object, full_validation, platform_version)?.into(), ), + 1 => Ok( + DataContractV1::from_value(raw_object, full_validation, platform_version)?.into(), + ), version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::from_object".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } @@ -32,12 +36,14 @@ impl DataContractValueConversionMethodsV0 for DataContract { fn to_value(&self, platform_version: &PlatformVersion) -> Result { match self { DataContract::V0(v0) => v0.to_value(platform_version), + DataContract::V1(v1) => v1.to_value(platform_version), } } fn into_value(self, platform_version: &PlatformVersion) -> Result { match self { DataContract::V0(v0) => v0.into_value(platform_version), + DataContract::V1(v1) => v1.into_value(platform_version), } } } diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs index c9c8ee76e9..cdd1666e02 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use crate::data_contract::document_type::v0::DocumentTypeV0; use crate::data_contract::document_type::DocumentType; @@ -41,6 +42,7 @@ impl DocumentType { documents_mutable_contract_default: bool, documents_can_be_deleted_contract_default: bool, full_validation: bool, + has_tokens: bool, validation_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result, ProtocolError> { @@ -62,9 +64,22 @@ impl DocumentType { validation_operations, platform_version, ), + // in v1 we add the ability to have contracts without documents and just tokens + 1 => DocumentTypeV0::create_document_types_from_document_schemas_v1( + data_contract_id, + document_schemas, + schema_defs, + documents_keep_history_contract_default, + documents_mutable_contract_default, + documents_can_be_deleted_contract_default, + full_validation, + has_tokens, + validation_operations, + platform_version, + ), version => Err(ProtocolError::UnknownVersionMismatch { method: "create_document_types_from_document_schemas".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs index 1050a4c228..69b497eeea 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v0/mod.rs @@ -88,6 +88,7 @@ mod tests { false, false, false, + false, &mut vec![], PlatformVersion::latest(), ); diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v1/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v1/mod.rs new file mode 100644 index 0000000000..720dc9fe83 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/create_document_types_from_document_schemas/v1/mod.rs @@ -0,0 +1,66 @@ +use crate::consensus::basic::data_contract::DocumentTypesAreMissingError; +use crate::data_contract::document_type::class_methods::consensus_or_protocol_data_contract_error; +use crate::data_contract::document_type::v0::DocumentTypeV0; +use crate::data_contract::document_type::DocumentType; +use crate::data_contract::DocumentName; +use crate::validation::operations::ProtocolValidationOperation; +use crate::version::PlatformVersion; +use crate::ProtocolError; +use platform_value::{Identifier, Value}; +use std::collections::BTreeMap; + +impl DocumentTypeV0 { + pub(in crate::data_contract) fn create_document_types_from_document_schemas_v1( + data_contract_id: Identifier, + document_schemas: BTreeMap, + schema_defs: Option<&BTreeMap>, + documents_keep_history_contract_default: bool, + documents_mutable_contract_default: bool, + documents_can_be_deleted_contract_default: bool, + full_validation: bool, + has_tokens: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, ProtocolError> { + let mut contract_document_types: BTreeMap = BTreeMap::new(); + + if document_schemas.is_empty() && !has_tokens { + return Err(consensus_or_protocol_data_contract_error( + DocumentTypesAreMissingError::new(data_contract_id).into(), + )); + } + + for (name, schema) in document_schemas.into_iter() { + let document_type = match platform_version + .dpp + .contract_versions + .document_type_versions + .structure_version + { + 0 => DocumentType::try_from_schema( + data_contract_id, + &name, + schema, + schema_defs, + documents_keep_history_contract_default, + documents_mutable_contract_default, + documents_can_be_deleted_contract_default, + full_validation, + validation_operations, + platform_version, + )?, + version => { + return Err(ProtocolError::UnknownVersionMismatch { + method: "get_document_types_from_value_array_v0 inner document type" + .to_string(), + known_versions: vec![0], + received: version, + }) + } + }; + + contract_document_types.insert(name.to_string(), document_type); + } + Ok(contract_document_types) + } +} diff --git a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs index 57b3bffb37..3394b0f6fc 100644 --- a/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v0/mod.rs @@ -744,7 +744,53 @@ fn insert_values_nested( let is_transient = known_transient.contains(&property_key); let field_type = match type_value { - "integer" => DocumentPropertyType::I64, + "integer" => { + DocumentPropertyType::I64 + // todo: we might want to do the following in the future (must be versioned) + // let minimum = inner_properties.get_optional_integer::(property_names::MINIMUM)?; + // let maximum = inner_properties.get_optional_integer::(property_names::MAXIMUM)?; + // + // match (minimum, maximum) { + // (Some(min), Some(max)) => { + // if min >= 0 { + // if max <= u8::MAX as i64 { + // DocumentPropertyType::U8 + // } else if max <= u16::MAX as i64 { + // DocumentPropertyType::U16 + // } else if max <= u32::MAX as i64 { + // DocumentPropertyType::U32 + // } else { + // DocumentPropertyType::U64 + // } + // } else { + // if min >= i8::MIN as i64 && max <= i8::MAX as i64 { + // DocumentPropertyType::I8 + // } else if min >= i16::MIN as i64 && max <= i16::MAX as i64 { + // DocumentPropertyType::I16 + // } else if min >= i32::MIN as i64 && max <= i32::MAX as i64 { + // DocumentPropertyType::I32 + // } else { + // DocumentPropertyType::I64 + // } + // } + // } + // (Some(min), None) => { + // if min >= 0 { + // DocumentPropertyType::U64 + // } else { + // DocumentPropertyType::I64 + // } + // } + // (None, Some(max)) => { + // if max >= 0 { + // DocumentPropertyType::U64 + // } else { + // DocumentPropertyType::I64 + // } + // } + // (None, None) => DocumentPropertyType::I64, + // } + } "number" => DocumentPropertyType::F64, "string" => DocumentPropertyType::String(StringPropertySizes { min_length: inner_properties.get_optional_integer(property_names::MIN_LENGTH)?, diff --git a/packages/rs-dpp/src/data_contract/document_type/mod.rs b/packages/rs-dpp/src/data_contract/document_type/mod.rs index a87ceb3c9c..23382dab53 100644 --- a/packages/rs-dpp/src/data_contract/document_type/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/mod.rs @@ -53,6 +53,8 @@ mod property_names { pub const CREATED_AT: &str = "$createdAt"; pub const UPDATED_AT: &str = "$updatedAt"; pub const TRANSFERRED_AT: &str = "$transferredAt"; + pub const MINIMUM: &str = "minimum"; + pub const MAXIMUM: &str = "maximum"; pub const MIN_ITEMS: &str = "minItems"; pub const MAX_ITEMS: &str = "maxItems"; pub const MIN_LENGTH: &str = "minLength"; diff --git a/packages/rs-dpp/src/data_contract/document_type/property/mod.rs b/packages/rs-dpp/src/data_contract/document_type/property/mod.rs index 927fb561a1..e95fa7560a 100644 --- a/packages/rs-dpp/src/data_contract/document_type/property/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/property/mod.rs @@ -1730,6 +1730,7 @@ impl DocumentPropertyType { } pub fn encode_u16(val: u16) -> Vec { + //todo this should just be to_be_bytes (and for all unsigned integers) // Positive integers are represented in binary with the signed bit set to 0 // Negative integers are represented in 2's complement form @@ -1754,7 +1755,7 @@ impl DocumentPropertyType { wtr } - /// Decodes an unsigned integer on 32 bits. + /// Decodes an unsigned integer on 16 bits. pub fn decode_u16(val: &[u8]) -> Option { // Flip the sign bit // to deal with interaction between the domains diff --git a/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs b/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs index 81194382f4..e875a6fe2c 100644 --- a/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/restricted_creation/mod.rs @@ -1,8 +1,8 @@ use crate::consensus::basic::data_contract::UnknownDocumentCreationRestrictionModeError; use crate::consensus::basic::BasicError; use crate::consensus::ConsensusError; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::ProtocolError; +use bincode::{Decode, Encode}; use std::fmt; use std::fmt::{Display, Formatter}; diff --git a/packages/rs-dpp/src/data_contract/document_type/schema/enrich_with_base_schema/v0/mod.rs b/packages/rs-dpp/src/data_contract/document_type/schema/enrich_with_base_schema/v0/mod.rs index 3560e2b930..620fb15497 100644 --- a/packages/rs-dpp/src/data_contract/document_type/schema/enrich_with_base_schema/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/document_type/schema/enrich_with_base_schema/v0/mod.rs @@ -1,11 +1,14 @@ use crate::data_contract::document_type::property_names; use crate::data_contract::errors::DataContractError; -use crate::data_contract::serialized_version::v0::property_names as contract_property_names; +use crate::data_contract::serialized_version::property_names as contract_property_names; use platform_value::{Value, ValueMapHelper}; pub const DATA_CONTRACT_SCHEMA_URI_V0: &str = "https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/document-meta.json"; +pub const TOKEN_SCHEMA_URI_V0: &str = + "https://github.com/dashpay/platform/blob/master/packages/rs-dpp/schema/meta_schemas/document/v0/token-meta.json"; + pub const PROPERTY_SCHEMA: &str = "$schema"; const SYSTEM_GENERATED_FIELDS: [&str; 9] = [ diff --git a/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs b/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs index beafe720de..67ab7eb856 100644 --- a/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs +++ b/packages/rs-dpp/src/data_contract/extra/drive_api_tests.rs @@ -107,7 +107,6 @@ mod test { let data_contract = DataContract::from_cbor(cbor_bytes, true, platform_version) .expect("contract should be deserialized"); - assert_eq!(0, data_contract.feature_version()); assert_eq!(expect_id, data_contract.id().as_bytes()); assert_eq!(expect_owner_id, data_contract.owner_id().as_bytes()); @@ -143,7 +142,7 @@ mod test { platform_version, ) .expect("expected to get a contract") - .into_v0() + .into_latest() .unwrap(); assert!(contract.config.documents_mutable_contract_default()); @@ -196,6 +195,58 @@ mod test { assert!(contact_info_indices[1].properties[0].ascending); } + #[test] + #[cfg(feature = "data-contract-cbor-conversion")] + fn mutability_properties_should_be_stored_and_restored_during_cbor_serialization_contract_v0() { + let platform_version = PlatformVersion::get(7).expect("expected version 7"); + + let mut contract = json_document_to_contract( + "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json", + false, + platform_version, + ) + .expect("expected to get a cbor document") + .into_v0() + .unwrap(); + + assert!(!contract.config().readonly()); + assert!(!contract.config.keeps_history()); + assert!(contract.config.documents_mutable_contract_default()); + assert!(!contract.config.documents_keep_history_contract_default()); + + contract.config.set_readonly(true); + contract.config.set_keeps_history(true); + contract + .config + .set_documents_mutable_contract_default(false); + contract + .config + .set_documents_can_be_deleted_contract_default(false); + contract + .config + .set_documents_keep_history_contract_default(true); + + let contract_cbor = contract + .to_cbor(platform_version) + .expect("serialization shouldn't fail"); + let deserialized_contract = DataContract::from_cbor(contract_cbor, true, platform_version) + .expect("deserialization shouldn't fail"); + + assert_matches!( + deserialized_contract.config(), + DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: true, + keeps_history: true, + documents_mutable_contract_default: false, + documents_keep_history_contract_default: true, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }) + ); + } + #[test] #[cfg(feature = "data-contract-cbor-conversion")] fn mutability_properties_should_be_stored_and_restored_during_cbor_serialization() { @@ -207,7 +258,7 @@ mod test { platform_version, ) .expect("expected to get a cbor document") - .into_v0() + .into_v1() .unwrap(); assert!(!contract.config().readonly()); @@ -259,7 +310,7 @@ mod test { ) .expect("expected to decode a contract"); - let contract_v0 = contract.as_v0_mut().unwrap(); + let contract_v0 = contract.as_latest_mut().unwrap(); assert!(!contract_v0.config().readonly()); assert!(!contract_v0.config.keeps_history()); @@ -286,7 +337,7 @@ mod test { .expect("deserialization shouldn't fail"); assert_eq!( - deserialized_contract.as_v0().unwrap().config, + deserialized_contract.as_latest().unwrap().config, DataContractConfig::V0(DataContractConfigV0 { can_be_deleted: false, readonly: true, diff --git a/packages/rs-dpp/src/data_contract/factory/v0/mod.rs b/packages/rs-dpp/src/data_contract/factory/v0/mod.rs index 7b9949e5f8..0c07d25a61 100644 --- a/packages/rs-dpp/src/data_contract/factory/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/factory/v0/mod.rs @@ -9,10 +9,10 @@ use crate::data_contract::config::DataContractConfig; #[cfg(feature = "data-contract-value-conversion")] use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; use crate::data_contract::created_data_contract::CreatedDataContract; -#[cfg(feature = "data-contract-value-conversion")] -use crate::data_contract::data_contract::DataContractV0; use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0; use crate::data_contract::serialized_version::DataContractInSerializationFormat; +#[cfg(feature = "data-contract-value-conversion")] +use crate::data_contract::v0::DataContractV0; use crate::data_contract::{DataContract, INITIAL_DATA_CONTRACT_VERSION}; use crate::serialization::PlatformDeserializableWithPotentialValidationFromVersionedStructure; #[cfg(feature = "state-transitions")] @@ -20,6 +20,7 @@ use crate::state_transition::data_contract_create_transition::DataContractCreate #[cfg(feature = "state-transitions")] use crate::state_transition::data_contract_update_transition::DataContractUpdateTransition; +use crate::data_contract::v1::DataContractV1; use crate::prelude::IdentityNonce; use crate::version::PlatformVersion; use crate::{errors::ProtocolError, prelude::Identifier}; @@ -117,9 +118,15 @@ impl DataContractFactoryV0 { platform_version, )? .into()), + 1 => Ok(DataContractV1::from_value( + data_contract_object, + full_validation, + platform_version, + )? + .into()), version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContractFactoryV0::create_from_object".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } diff --git a/packages/rs-dpp/src/data_contract/group/accessors/mod.rs b/packages/rs-dpp/src/data_contract/group/accessors/mod.rs new file mode 100644 index 0000000000..2d24cd45f5 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/group/accessors/mod.rs @@ -0,0 +1 @@ +pub mod v0; diff --git a/packages/rs-dpp/src/data_contract/group/accessors/v0/mod.rs b/packages/rs-dpp/src/data_contract/group/accessors/v0/mod.rs new file mode 100644 index 0000000000..55353dd047 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/group/accessors/v0/mod.rs @@ -0,0 +1,33 @@ +use crate::data_contract::group::GroupRequiredPower; +use crate::ProtocolError; +use platform_value::Identifier; +use std::collections::BTreeMap; + +/// Getters for GroupV0 +pub trait GroupV0Getters { + /// Returns the member power + fn member_power(&self, member_id: Identifier) -> Result; + /// Returns the members map of the group + fn members(&self) -> &BTreeMap; + + /// Returns a mutable reference to the members map of the group + fn members_mut(&mut self) -> &mut BTreeMap; + + /// Returns the required power of the group + fn required_power(&self) -> GroupRequiredPower; +} + +/// Setters for GroupV0 +pub trait GroupV0Setters { + /// Sets the members of the group + fn set_members(&mut self, members: BTreeMap); + + /// Inserts or updates a member with a specific power + fn set_member_power(&mut self, member_id: Identifier, power: u32); + + /// Removes a member from the group + fn remove_member(&mut self, member_id: &Identifier) -> bool; + + /// Sets the required power of the group + fn set_required_power(&mut self, required_power: GroupRequiredPower); +} diff --git a/packages/rs-dpp/src/data_contract/group/mod.rs b/packages/rs-dpp/src/data_contract/group/mod.rs new file mode 100644 index 0000000000..26e3c03629 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/group/mod.rs @@ -0,0 +1,83 @@ +use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; +use crate::data_contract::group::v0::GroupV0; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +pub mod accessors; +pub mod v0; +pub type RequiredSigners = u8; + +pub type GroupMemberPower = u32; +pub type GroupSumPower = u32; +pub type GroupRequiredPower = u32; +#[derive( + Serialize, + Deserialize, + Decode, + Encode, + PlatformSerialize, + PlatformDeserialize, + Debug, + Clone, + PartialEq, + Eq, +)] +#[platform_serialize(unversioned)] +pub enum Group { + V0(GroupV0), +} + +impl GroupV0Getters for Group { + fn member_power(&self, member_id: Identifier) -> Result { + match self { + Group::V0(group_v0) => group_v0.member_power(member_id), + } + } + fn members(&self) -> &BTreeMap { + match self { + Group::V0(group_v0) => group_v0.members(), + } + } + + fn members_mut(&mut self) -> &mut BTreeMap { + match self { + Group::V0(group_v0) => group_v0.members_mut(), + } + } + + fn required_power(&self) -> GroupRequiredPower { + match self { + Group::V0(group_v0) => group_v0.required_power(), + } + } +} + +impl GroupV0Setters for Group { + fn set_members(&mut self, members: BTreeMap) { + match self { + Group::V0(group_v0) => group_v0.set_members(members), + } + } + + fn set_member_power(&mut self, member_id: Identifier, power: u32) { + match self { + Group::V0(group_v0) => group_v0.set_member_power(member_id, power), + } + } + + fn remove_member(&mut self, member_id: &Identifier) -> bool { + match self { + Group::V0(group_v0) => group_v0.remove_member(member_id), + } + } + + fn set_required_power(&mut self, required_power: GroupRequiredPower) { + match self { + Group::V0(group_v0) => group_v0.set_required_power(required_power), + } + } +} diff --git a/packages/rs-dpp/src/data_contract/group/v0/mod.rs b/packages/rs-dpp/src/data_contract/group/v0/mod.rs new file mode 100644 index 0000000000..c53696e9b2 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/group/v0/mod.rs @@ -0,0 +1,68 @@ +use crate::data_contract::group::accessors::v0::{GroupV0Getters, GroupV0Setters}; +use crate::data_contract::group::{GroupMemberPower, GroupRequiredPower}; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive( + Serialize, + Deserialize, + Decode, + Encode, + PlatformSerialize, + PlatformDeserialize, + Debug, + Clone, + PartialEq, + Eq, +)] +#[platform_serialize(unversioned)] +pub struct GroupV0 { + pub members: BTreeMap, + pub required_power: GroupRequiredPower, +} + +impl GroupV0Getters for GroupV0 { + fn member_power(&self, member_id: Identifier) -> Result { + self.members + .get(&member_id) + .cloned() + .ok_or(ProtocolError::GroupMemberNotFound(format!( + "Group member {} not found", + member_id + ))) + } + + fn members(&self) -> &BTreeMap { + &self.members + } + + fn members_mut(&mut self) -> &mut BTreeMap { + &mut self.members + } + + fn required_power(&self) -> GroupRequiredPower { + self.required_power + } +} + +impl GroupV0Setters for GroupV0 { + fn set_members(&mut self, members: BTreeMap) { + self.members = members; + } + + fn set_member_power(&mut self, member_id: Identifier, power: u32) { + self.members.insert(member_id, power); + } + + fn remove_member(&mut self, member_id: &Identifier) -> bool { + self.members.remove(member_id).is_some() + } + + fn set_required_power(&mut self, required_power: GroupRequiredPower) { + self.required_power = required_power; + } +} diff --git a/packages/rs-dpp/src/data_contract/methods/schema/mod.rs b/packages/rs-dpp/src/data_contract/methods/schema/mod.rs index 63748fb45f..b048cd44ff 100644 --- a/packages/rs-dpp/src/data_contract/methods/schema/mod.rs +++ b/packages/rs-dpp/src/data_contract/methods/schema/mod.rs @@ -26,6 +26,13 @@ impl DataContractSchemaMethodsV0 for DataContract { validation_operations, platform_version, ), + DataContract::V1(v1) => v1.set_document_schemas( + schemas, + defs, + full_validation, + validation_operations, + platform_version, + ), } } @@ -45,18 +52,27 @@ impl DataContractSchemaMethodsV0 for DataContract { validation_operations, platform_version, ), + DataContract::V1(v1) => v1.set_document_schema( + name, + schema, + full_validation, + validation_operations, + platform_version, + ), } } fn document_schemas(&self) -> BTreeMap { match self { DataContract::V0(v0) => v0.document_schemas(), + DataContract::V1(v1) => v1.document_schemas(), } } fn schema_defs(&self) -> Option<&BTreeMap> { match self { DataContract::V0(v0) => v0.schema_defs(), + DataContract::V1(v1) => v1.schema_defs(), } } @@ -74,6 +90,12 @@ impl DataContractSchemaMethodsV0 for DataContract { validation_operations, platform_version, ), + DataContract::V1(v1) => v1.set_schema_defs( + defs, + full_validation, + validation_operations, + platform_version, + ), } } } diff --git a/packages/rs-dpp/src/data_contract/mod.rs b/packages/rs-dpp/src/data_contract/mod.rs index 5fd8f7b56f..818bc3f621 100644 --- a/packages/rs-dpp/src/data_contract/mod.rs +++ b/packages/rs-dpp/src/data_contract/mod.rs @@ -3,10 +3,12 @@ use crate::serialization::{ PlatformDeserializableWithPotentialValidationFromVersionedStructure, PlatformLimitDeserializableFromVersionedStructure, PlatformSerializableWithPlatformVersion, }; +use std::collections::BTreeMap; use derive_more::From; use bincode::config::{BigEndian, Configuration}; +use once_cell::sync::Lazy; pub mod errors; pub mod extra; @@ -17,7 +19,8 @@ mod generate_data_contract; pub mod created_data_contract; pub mod document_type; -mod v0; +pub mod v0; +pub mod v1; #[cfg(feature = "factories")] pub mod factory; @@ -32,11 +35,12 @@ mod methods; pub mod serialized_version; pub use methods::*; pub mod accessors; +pub mod associated_token; +pub mod change_control_rules; pub mod config; +pub mod group; pub mod storage_requirements; -pub use v0::*; - use crate::data_contract::serialized_version::{ DataContractInSerializationFormat, CONTRACT_DESERIALIZATION_LIMIT, }; @@ -46,6 +50,10 @@ use crate::version::{FeatureVersion, PlatformVersion}; use crate::ProtocolError; use crate::ProtocolError::{PlatformDeserializationError, PlatformSerializationError}; +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::group::Group; +use crate::data_contract::v0::DataContractV0; +use crate::data_contract::v1::DataContractV1; use platform_version::TryIntoPlatformVersioned; use platform_versioning::PlatformVersioned; pub use serde_json::Value as JsonValue; @@ -53,10 +61,18 @@ pub use serde_json::Value as JsonValue; type JsonSchema = JsonValue; type DefinitionName = String; pub type DocumentName = String; +pub type TokenName = String; +pub type GroupContractPosition = u16; +pub type TokenContractPosition = u16; type PropertyPath = String; pub const INITIAL_DATA_CONTRACT_VERSION: u32 = 1; +// Define static empty BTreeMaps +static EMPTY_GROUPS: Lazy> = Lazy::new(|| BTreeMap::new()); +static EMPTY_TOKENS: Lazy> = + Lazy::new(|| BTreeMap::new()); + /// Understanding Data Contract versioning /// Data contract versioning is both for the code structure and for serialization. /// @@ -85,6 +101,7 @@ pub const INITIAL_DATA_CONTRACT_VERSION: u32 = 1; #[derive(Debug, Clone, PartialEq, From, PlatformVersioned)] pub enum DataContract { V0(DataContractV0), + V1(DataContractV1), } impl PlatformSerializableWithPlatformVersion for DataContract { @@ -214,18 +231,66 @@ impl DataContract { pub fn as_v0(&self) -> Option<&DataContractV0> { match self { DataContract::V0(v0) => Some(v0), + _ => None, } } pub fn as_v0_mut(&mut self) -> Option<&mut DataContractV0> { match self { DataContract::V0(v0) => Some(v0), + _ => None, } } pub fn into_v0(self) -> Option { match self { DataContract::V0(v0) => Some(v0), + _ => None, + } + } + + pub fn as_v1(&self) -> Option<&DataContractV1> { + match self { + DataContract::V1(v1) => Some(v1), + _ => None, + } + } + + pub fn as_v1_mut(&mut self) -> Option<&mut DataContractV1> { + match self { + DataContract::V1(v1) => Some(v1), + _ => None, + } + } + + pub fn into_v1(self) -> Option { + match self { + DataContract::V1(v1) => Some(v1), + _ => None, + } + } + + /// This should only ever be used in tests, as it will change + #[cfg(test)] + pub fn into_latest(self) -> Option { + self.into_v1() + } + + /// This should only ever be used in tests, as it will change + #[cfg(test)] + pub fn as_latest(&self) -> Option<&DataContractV1> { + match self { + DataContract::V1(v1) => Some(v1), + _ => None, + } + } + + /// This should only ever be used in tests, as it will change + #[cfg(test)] + pub fn as_latest_mut(&mut self) -> Option<&mut DataContractV1> { + match self { + DataContract::V1(v1) => Some(v1), + _ => None, } } diff --git a/packages/rs-dpp/src/data_contract/serialized_version/mod.rs b/packages/rs-dpp/src/data_contract/serialized_version/mod.rs index 150bc6a28b..a88d93413b 100644 --- a/packages/rs-dpp/src/data_contract/serialized_version/mod.rs +++ b/packages/rs-dpp/src/data_contract/serialized_version/mod.rs @@ -1,9 +1,16 @@ -use crate::data_contract::data_contract::DataContractV0; use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0; -use crate::data_contract::{DataContract, DefinitionName, DocumentName}; +use crate::data_contract::{ + DataContract, DefinitionName, DocumentName, GroupContractPosition, TokenContractPosition, + EMPTY_GROUPS, EMPTY_TOKENS, +}; use crate::version::PlatformVersion; use std::collections::BTreeMap; +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::group::Group; +use crate::data_contract::serialized_version::v1::DataContractInSerializationFormatV1; +use crate::data_contract::v0::DataContractV0; +use crate::data_contract::v1::DataContractV1; use crate::validation::operations::ProtocolValidationOperation; use crate::ProtocolError; use bincode::{Decode, Encode}; @@ -15,6 +22,14 @@ use platform_versioning::PlatformVersioned; use serde::{Deserialize, Serialize}; pub(in crate::data_contract) mod v0; +pub(in crate::data_contract) mod v1; + +pub mod property_names { + pub const ID: &str = "id"; + pub const OWNER_ID: &str = "ownerId"; + pub const VERSION: &str = "version"; + pub const DEFINITIONS: &str = "$defs"; +} pub const CONTRACT_DESERIALIZATION_LIMIT: usize = 15000; @@ -27,6 +42,8 @@ pub const CONTRACT_DESERIALIZATION_LIMIT: usize = 15000; pub enum DataContractInSerializationFormat { #[cfg_attr(feature = "data-contract-serde-conversion", serde(rename = "0"))] V0(DataContractInSerializationFormatV0), + #[cfg_attr(feature = "data-contract-serde-conversion", serde(rename = "1"))] + V1(DataContractInSerializationFormatV1), } impl DataContractInSerializationFormat { @@ -34,6 +51,7 @@ impl DataContractInSerializationFormat { pub fn id(&self) -> Identifier { match self { DataContractInSerializationFormat::V0(v0) => v0.id, + DataContractInSerializationFormat::V1(v1) => v1.id, } } @@ -41,24 +59,41 @@ impl DataContractInSerializationFormat { pub fn owner_id(&self) -> Identifier { match self { DataContractInSerializationFormat::V0(v0) => v0.owner_id, + DataContractInSerializationFormat::V1(v1) => v1.owner_id, } } pub fn document_schemas(&self) -> &BTreeMap { match self { DataContractInSerializationFormat::V0(v0) => &v0.document_schemas, + DataContractInSerializationFormat::V1(v1) => &v1.document_schemas, } } pub fn schema_defs(&self) -> Option<&BTreeMap> { match self { DataContractInSerializationFormat::V0(v0) => v0.schema_defs.as_ref(), + DataContractInSerializationFormat::V1(v1) => v1.schema_defs.as_ref(), } } pub fn version(&self) -> u32 { match self { DataContractInSerializationFormat::V0(v0) => v0.version, + DataContractInSerializationFormat::V1(v1) => v1.version, + } + } + + pub fn groups(&self) -> &BTreeMap { + match self { + DataContractInSerializationFormat::V0(_) => &EMPTY_GROUPS, + DataContractInSerializationFormat::V1(v1) => &v1.groups, + } + } + pub fn tokens(&self) -> &BTreeMap { + match self { + DataContractInSerializationFormat::V0(_) => &EMPTY_TOKENS, + DataContractInSerializationFormat::V1(v1) => &v1.tokens, } } } @@ -80,9 +115,13 @@ impl TryFromPlatformVersioned for DataContractInSerializationFor let v0_format: DataContractInSerializationFormatV0 = DataContract::V0(value).into(); Ok(v0_format.into()) } + 1 => { + let v1_format: DataContractInSerializationFormatV1 = DataContract::V0(value).into(); + Ok(v1_format.into()) + } version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::serialize_to_default_current_version".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } @@ -107,9 +146,76 @@ impl TryFromPlatformVersioned<&DataContractV0> for DataContractInSerializationFo DataContract::V0(value.to_owned()).into(); Ok(v0_format.into()) } + 1 => { + let v1_format: DataContractInSerializationFormatV1 = + DataContract::V0(value.to_owned()).into(); + Ok(v1_format.into()) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DataContract::serialize_to_default_current_version".to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } +} + +impl TryFromPlatformVersioned for DataContractInSerializationFormat { + type Error = ProtocolError; + + fn try_from_platform_versioned( + value: DataContractV1, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .contract_versions + .contract_serialization_version + .default_current_version + { + 0 => { + let v0_format: DataContractInSerializationFormatV0 = DataContract::V1(value).into(); + Ok(v0_format.into()) + } + 1 => { + let v1_format: DataContractInSerializationFormatV1 = DataContract::V1(value).into(); + Ok(v1_format.into()) + } version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::serialize_to_default_current_version".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], + received: version, + }), + } + } +} + +impl TryFromPlatformVersioned<&DataContractV1> for DataContractInSerializationFormat { + type Error = ProtocolError; + + fn try_from_platform_versioned( + value: &DataContractV1, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .contract_versions + .contract_serialization_version + .default_current_version + { + 0 => { + let v0_format: DataContractInSerializationFormatV0 = + DataContract::V1(value.to_owned()).into(); + Ok(v0_format.into()) + } + 1 => { + let v1_format: DataContractInSerializationFormatV1 = + DataContract::V1(value.to_owned()).into(); + Ok(v1_format.into()) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DataContract::serialize_to_default_current_version".to_string(), + known_versions: vec![0, 1], received: version, }), } @@ -133,9 +239,13 @@ impl TryFromPlatformVersioned<&DataContract> for DataContractInSerializationForm let v0_format: DataContractInSerializationFormatV0 = value.clone().into(); Ok(v0_format.into()) } + 1 => { + let v1_format: DataContractInSerializationFormatV1 = value.clone().into(); + Ok(v1_format.into()) + } version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::serialize_to_default_current_version".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } @@ -159,9 +269,13 @@ impl TryFromPlatformVersioned for DataContractInSerializationForma let v0_format: DataContractInSerializationFormatV0 = value.into(); Ok(v0_format.into()) } + 1 => { + let v1_format: DataContractInSerializationFormatV1 = value.into(); + Ok(v1_format.into()) + } version => Err(ProtocolError::UnknownVersionMismatch { method: "DataContract::serialize_consume_to_default_current_version".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, }), } @@ -175,29 +289,30 @@ impl DataContract { validation_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result { - match value { - DataContractInSerializationFormat::V0(serialization_format_v0) => { - match platform_version - .dpp - .contract_versions - .contract_structure_version - { - 0 => { - let data_contract = DataContractV0::try_from_platform_versioned_v0( - serialization_format_v0, - full_validation, - validation_operations, - platform_version, - )?; - Ok(data_contract.into()) - } - version => Err(ProtocolError::UnknownVersionMismatch { - method: "DataContract::from_serialization_format".to_string(), - known_versions: vec![0], - received: version, - }), - } - } + match platform_version + .dpp + .contract_versions + .contract_structure_version + { + 0 => DataContractV0::try_from_platform_versioned( + value, + full_validation, + validation_operations, + platform_version, + ) + .map(|contract| contract.into()), + 1 => DataContractV1::try_from_platform_versioned( + value, + full_validation, + validation_operations, + platform_version, + ) + .map(|contract| contract.into()), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DataContract::try_from_platform_versioned".to_string(), + known_versions: vec![0, 1], + received: version, + }), } } } diff --git a/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs b/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs index 085b1d2a82..6cd119e3bf 100644 --- a/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs +++ b/packages/rs-dpp/src/data_contract/serialized_version/v0/mod.rs @@ -3,19 +3,13 @@ use crate::data_contract::config::DataContractConfig; use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; use crate::data_contract::v0::DataContractV0; +use crate::data_contract::v1::DataContractV1; use crate::data_contract::{DataContract, DefinitionName, DocumentName}; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Decode, Encode}; use platform_value::{Identifier, Value}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -pub mod property_names { - pub const ID: &str = "id"; - pub const OWNER_ID: &str = "ownerId"; - pub const VERSION: &str = "version"; - pub const DEFINITIONS: &str = "$defs"; -} - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct DataContractInSerializationFormatV0 { @@ -53,6 +47,29 @@ impl From for DataContractInSerializationFormatV0 { .. } = v0; + DataContractInSerializationFormatV0 { + id, + config, + version, + owner_id, + document_schemas: document_types + .into_iter() + .map(|(key, document_type)| (key, document_type.schema_owned())) + .collect(), + schema_defs, + } + } + DataContract::V1(v1) => { + let DataContractV1 { + id, + config, + version, + owner_id, + schema_defs, + document_types, + .. + } = v1; + DataContractInSerializationFormatV0 { id, config, diff --git a/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs b/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs new file mode 100644 index 0000000000..d24ed1402c --- /dev/null +++ b/packages/rs-dpp/src/data_contract/serialized_version/v1/mod.rs @@ -0,0 +1,136 @@ +use crate::data_contract::config::v0::DataContractConfigV0; +use crate::data_contract::config::DataContractConfig; +use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; + +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::group::Group; +use crate::data_contract::v0::DataContractV0; +use crate::data_contract::v1::DataContractV1; +use crate::data_contract::{ + DataContract, DefinitionName, DocumentName, GroupContractPosition, TokenContractPosition, +}; +use bincode::{Decode, Encode}; +use platform_value::{Identifier, Value}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[serde(rename_all = "camelCase")] +pub struct DataContractInSerializationFormatV1 { + /// A unique identifier for the data contract. + pub id: Identifier, + + /// Internal configuration for the contract. + #[serde(default = "DataContractConfigV0::default_with_version")] + pub config: DataContractConfig, + + /// The version of this data contract. + pub version: u32, + + /// The identifier of the contract owner. + pub owner_id: Identifier, + + /// Shared subschemas to reuse across documents as $defs object + pub schema_defs: Option>, + + /// Document JSON Schemas per type + pub document_schemas: BTreeMap, + + /// Groups that allow for specific multiparty actions on the contract + #[serde(default, deserialize_with = "deserialize_u16_group_map")] + pub groups: BTreeMap, + + /// The tokens on the contract. + #[serde(default, deserialize_with = "deserialize_u16_token_configuration_map")] + pub tokens: BTreeMap, +} + +fn deserialize_u16_group_map<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let map: BTreeMap = BTreeMap::deserialize(deserializer)?; + map.into_iter() + .map(|(k, v)| { + k.parse::() + .map_err(serde::de::Error::custom) + .map(|key| (key, v)) + }) + .collect() +} +fn deserialize_u16_token_configuration_map<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let map: BTreeMap = BTreeMap::deserialize(deserializer)?; + map.into_iter() + .map(|(k, v)| { + k.parse::() + .map_err(serde::de::Error::custom) + .map(|key| (key, v)) + }) + .collect() +} + +impl From for DataContractInSerializationFormatV1 { + fn from(value: DataContract) -> Self { + match value { + DataContract::V0(v0) => { + let DataContractV0 { + id, + config, + version, + owner_id, + schema_defs, + document_types, + .. + } = v0; + + DataContractInSerializationFormatV1 { + id, + config, + version, + owner_id, + schema_defs, + document_schemas: document_types + .into_iter() + .map(|(key, document_type)| (key, document_type.schema_owned())) + .collect(), + groups: Default::default(), + tokens: Default::default(), + } + } + DataContract::V1(v1) => { + let DataContractV1 { + id, + config, + version, + owner_id, + schema_defs, + document_types, + groups, + tokens, + .. + } = v1; + + DataContractInSerializationFormatV1 { + id, + config, + version, + owner_id, + schema_defs, + document_schemas: document_types + .into_iter() + .map(|(key, document_type)| (key, document_type.schema_owned())) + .collect(), + groups, + tokens, + } + } + } + } +} diff --git a/packages/rs-dpp/src/data_contract/v0/conversion/cbor.rs b/packages/rs-dpp/src/data_contract/v0/conversion/cbor.rs index af497027fd..c2aba05b12 100644 --- a/packages/rs-dpp/src/data_contract/v0/conversion/cbor.rs +++ b/packages/rs-dpp/src/data_contract/v0/conversion/cbor.rs @@ -1,6 +1,6 @@ use crate::data_contract::conversion::cbor::DataContractCborConversionMethodsV0; use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; -use crate::data_contract::data_contract::DataContractV0; +use crate::data_contract::v0::DataContractV0; use crate::util::cbor_value::CborCanonicalMap; use crate::version::PlatformVersion; diff --git a/packages/rs-dpp/src/data_contract/v0/conversion/value.rs b/packages/rs-dpp/src/data_contract/v0/conversion/value.rs index 3ed0a98713..db16bc497d 100644 --- a/packages/rs-dpp/src/data_contract/v0/conversion/value.rs +++ b/packages/rs-dpp/src/data_contract/v0/conversion/value.rs @@ -1,9 +1,8 @@ use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; -use crate::data_contract::data_contract::DataContractV0; -use crate::data_contract::serialized_version::v0::{ - property_names, DataContractInSerializationFormatV0, -}; +use crate::data_contract::serialized_version::property_names; +use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0; use crate::data_contract::serialized_version::DataContractInSerializationFormat; +use crate::data_contract::v0::DataContractV0; use crate::version::PlatformVersion; use crate::ProtocolError; use platform_value::{ReplacementType, Value}; diff --git a/packages/rs-dpp/src/data_contract/v0/methods/schema.rs b/packages/rs-dpp/src/data_contract/v0/methods/schema.rs index d97cb54045..dddd285a6c 100644 --- a/packages/rs-dpp/src/data_contract/v0/methods/schema.rs +++ b/packages/rs-dpp/src/data_contract/v0/methods/schema.rs @@ -27,6 +27,7 @@ impl DataContractSchemaMethodsV0 for DataContractV0 { self.config.documents_mutable_contract_default(), self.config.documents_can_be_deleted_contract_default(), full_validation, + false, validation_operations, platform_version, )?; diff --git a/packages/rs-dpp/src/data_contract/v0/serialization/bincode.rs b/packages/rs-dpp/src/data_contract/v0/serialization/bincode.rs deleted file mode 100644 index 65d78beaa1..0000000000 --- a/packages/rs-dpp/src/data_contract/v0/serialization/bincode.rs +++ /dev/null @@ -1,31 +0,0 @@ -#[cfg(test)] -mod tests { - use crate::data_contract::DataContract; - use crate::identity::accessors::IdentityGettersV0; - use crate::identity::Identity; - use crate::serialization::{ - PlatformDeserializableWithPotentialValidationFromVersionedStructure, - PlatformSerializableWithPlatformVersion, - }; - use crate::tests::fixtures::get_data_contract_fixture; - use crate::version::PlatformVersion; - use platform_version::version::LATEST_PLATFORM_VERSION; - - #[test] - #[cfg(feature = "random-identities")] - fn data_contract_ser_de() { - let platform_version = PlatformVersion::latest(); - let identity = Identity::random_identity(5, Some(5), platform_version) - .expect("expected a random identity"); - let contract = - get_data_contract_fixture(Some(identity.id()), 0, platform_version.protocol_version) - .data_contract_owned(); - let bytes = contract - .serialize_to_bytes_with_platform_version(LATEST_PLATFORM_VERSION) - .expect("expected to serialize"); - let recovered_contract = - DataContract::versioned_deserialize(&bytes, false, platform_version) - .expect("expected to deserialize state transition"); - assert_eq!(contract, recovered_contract); - } -} diff --git a/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs b/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs index 104ede8844..2a79edd362 100644 --- a/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs +++ b/packages/rs-dpp/src/data_contract/v0/serialization/mod.rs @@ -7,11 +7,10 @@ use crate::data_contract::DataContract; use crate::version::{PlatformVersion, PlatformVersionCurrentVersion}; use crate::ProtocolError; +use crate::data_contract::serialized_version::v1::DataContractInSerializationFormatV1; use crate::validation::operations::ProtocolValidationOperation; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -pub mod bincode; - impl Serialize for DataContractV0 { fn serialize(&self, serializer: S) -> Result where @@ -51,27 +50,24 @@ impl DataContractV0 { ) -> Result { match value { DataContractInSerializationFormat::V0(serialization_format_v0) => { - match platform_version - .dpp - .contract_versions - .contract_structure_version - { - 0 => { - let data_contract = DataContractV0::try_from_platform_versioned_v0( - serialization_format_v0, - full_validation, - validation_operations, - platform_version, - )?; - - Ok(data_contract) - } - version => Err(ProtocolError::UnknownVersionMismatch { - method: "DataContractV0::from_serialization_format".to_string(), - known_versions: vec![0], - received: version, - }), - } + let data_contract = DataContractV0::try_from_platform_versioned_v0( + serialization_format_v0, + full_validation, + validation_operations, + platform_version, + )?; + + Ok(data_contract) + } + DataContractInSerializationFormat::V1(serialization_format_v1) => { + let data_contract = DataContractV0::try_from_platform_versioned_v1( + serialization_format_v1, + full_validation, + validation_operations, + platform_version, + )?; + + Ok(data_contract) } } } @@ -99,6 +95,7 @@ impl DataContractV0 { config.documents_mutable_contract_default(), config.documents_can_be_deleted_contract_default(), full_validation, + false, validation_operations, platform_version, )?; @@ -115,4 +112,78 @@ impl DataContractV0 { Ok(data_contract) } + + pub(in crate::data_contract) fn try_from_platform_versioned_v1( + data_contract_data: DataContractInSerializationFormatV1, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + let DataContractInSerializationFormatV1 { + id, + config, + version, + owner_id, + document_schemas, + schema_defs, + .. + } = data_contract_data; + + let document_types = DocumentType::create_document_types_from_document_schemas( + id, + document_schemas, + schema_defs.as_ref(), + config.documents_keep_history_contract_default(), + config.documents_mutable_contract_default(), + config.documents_can_be_deleted_contract_default(), + full_validation, + false, + validation_operations, + platform_version, + )?; + + let data_contract = DataContractV0 { + id, + version, + owner_id, + document_types, + metadata: None, + config, + schema_defs, + }; + + Ok(data_contract) + } +} + +#[cfg(test)] +mod tests { + use crate::data_contract::DataContract; + use crate::identity::accessors::IdentityGettersV0; + use crate::identity::Identity; + use crate::serialization::{ + PlatformDeserializableWithPotentialValidationFromVersionedStructure, + PlatformSerializableWithPlatformVersion, + }; + use crate::tests::fixtures::get_data_contract_fixture; + use crate::version::PlatformVersion; + use platform_version::version::LATEST_PLATFORM_VERSION; + + #[test] + #[cfg(feature = "random-identities")] + fn data_contract_ser_de() { + let platform_version = PlatformVersion::first(); + let identity = Identity::random_identity(5, Some(5), platform_version) + .expect("expected a random identity"); + let contract = + get_data_contract_fixture(Some(identity.id()), 0, platform_version.protocol_version) + .data_contract_owned(); + let bytes = contract + .serialize_to_bytes_with_platform_version(LATEST_PLATFORM_VERSION) + .expect("expected to serialize"); + let recovered_contract = + DataContract::versioned_deserialize(&bytes, false, platform_version) + .expect("expected to deserialize state transition"); + assert_eq!(contract, recovered_contract); + } } diff --git a/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs b/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs new file mode 100644 index 0000000000..d62a46ddfd --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/accessors/mod.rs @@ -0,0 +1,225 @@ +use crate::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; +use crate::data_contract::config::DataContractConfig; +use crate::data_contract::document_type::{DocumentType, DocumentTypeRef}; +use crate::data_contract::errors::DataContractError; + +use crate::data_contract::v1::DataContractV1; +use crate::data_contract::{DocumentName, GroupContractPosition, TokenContractPosition}; +use crate::metadata::Metadata; + +use crate::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; +use crate::data_contract::group::Group; +use crate::tokens::calculate_token_id; +use crate::tokens::errors::TokenError; +use crate::ProtocolError; +use platform_value::Identifier; +use std::collections::BTreeMap; + +impl DataContractV0Getters for DataContractV1 { + fn id(&self) -> Identifier { + self.id + } + + fn id_ref(&self) -> &Identifier { + &self.id + } + + fn version(&self) -> u32 { + self.version + } + + fn owner_id(&self) -> Identifier { + self.owner_id + } + + fn document_type_cloned_for_name(&self, name: &str) -> Result { + self.document_type_cloned_optional_for_name(name) + .ok_or_else(|| { + DataContractError::DocumentTypeNotFound( + "can not get document type from contract".to_string(), + ) + }) + } + + fn document_type_borrowed_for_name( + &self, + name: &str, + ) -> Result<&DocumentType, DataContractError> { + self.document_types.get(name).ok_or_else(|| { + DataContractError::DocumentTypeNotFound( + "can not get document type from contract".to_string(), + ) + }) + } + + fn document_type_for_name(&self, name: &str) -> Result { + self.document_type_optional_for_name(name).ok_or_else(|| { + DataContractError::DocumentTypeNotFound( + "can not get document type from contract".to_string(), + ) + }) + } + + fn document_type_optional_for_name(&self, name: &str) -> Option { + self.document_types + .get(name) + .map(|document_type| document_type.as_ref()) + } + + fn document_type_cloned_optional_for_name(&self, name: &str) -> Option { + self.document_types.get(name).cloned() + } + + fn has_document_type_for_name(&self, name: &str) -> bool { + self.document_types.get(name).is_some() + } + + fn document_types_with_contested_indexes(&self) -> BTreeMap<&DocumentName, &DocumentType> { + self.document_types + .iter() + .filter(|(_, document_type)| { + document_type + .indexes() + .iter() + .any(|(_, index)| index.contested_index.is_some()) + }) + .collect() + } + + fn document_types(&self) -> &BTreeMap { + &self.document_types + } + + fn document_types_mut(&mut self) -> &mut BTreeMap { + &mut self.document_types + } + + fn metadata(&self) -> Option<&Metadata> { + self.metadata.as_ref() + } + + fn metadata_mut(&mut self) -> Option<&mut Metadata> { + self.metadata.as_mut() + } + + fn config(&self) -> &DataContractConfig { + &self.config + } + + fn config_mut(&mut self) -> &mut DataContractConfig { + &mut self.config + } +} + +impl DataContractV0Setters for DataContractV1 { + fn set_id(&mut self, id: Identifier) { + self.id = id; + + self.document_types + .iter_mut() + .for_each(|(_, document_type)| match document_type { + DocumentType::V0(v0) => v0.data_contract_id = id, + }) + } + + fn set_version(&mut self, version: u32) { + self.version = version; + } + + fn increment_version(&mut self) { + self.version += 1; + } + + fn set_owner_id(&mut self, owner_id: Identifier) { + self.owner_id = owner_id; + } + + fn set_metadata(&mut self, metadata: Option) { + self.metadata = metadata; + } + + fn set_config(&mut self, config: DataContractConfig) { + self.config = config; + } +} + +impl DataContractV1Getters for DataContractV1 { + fn group(&self, position: GroupContractPosition) -> Result<&Group, ProtocolError> { + self.groups + .get(&position) + .ok_or(ProtocolError::GroupNotFound(format!( + "Group not found in contract {} at position {}", + self.id(), + position + ))) + } + + fn groups(&self) -> &BTreeMap { + &self.groups + } + + fn groups_mut(&mut self) -> Option<&mut BTreeMap> { + Some(&mut self.groups) + } + + fn expected_group(&self, position: GroupContractPosition) -> Result<&Group, ProtocolError> { + self.groups + .get(&position) + .ok_or(ProtocolError::GroupNotFound(format!( + "Group not found at position {} in contract {}", + position, + self.id() + ))) + } + + fn tokens(&self) -> &BTreeMap { + &self.tokens + } + + fn tokens_mut(&mut self) -> Option<&mut BTreeMap> { + Some(&mut self.tokens) + } + + fn expected_token_configuration( + &self, + position: TokenContractPosition, + ) -> Result<&TokenConfiguration, ProtocolError> { + self.tokens.get(&position).ok_or(ProtocolError::Token( + TokenError::TokenNotFoundAtPositionError.into(), + )) + } + + fn token_configuration_mut( + &mut self, + position: TokenContractPosition, + ) -> Option<&mut TokenConfiguration> { + self.tokens.get_mut(&position) + } + + /// Returns the token id if a token exists at that position + fn token_id(&self, position: TokenContractPosition) -> Option { + self.tokens + .get(&position) + .map(|_| calculate_token_id(self.id.as_bytes(), position).into()) + } +} + +impl DataContractV1Setters for DataContractV1 { + fn set_groups(&mut self, groups: BTreeMap) { + self.groups = groups; + } + + fn set_tokens(&mut self, tokens: BTreeMap) { + self.tokens = tokens; + } + + fn add_group(&mut self, group_position: GroupContractPosition, group: Group) { + self.groups.insert(group_position, group); + } + + fn add_token(&mut self, name: TokenContractPosition, token: TokenConfiguration) { + self.tokens.insert(name, token); + } +} diff --git a/packages/rs-dpp/src/data_contract/v1/conversion/cbor.rs b/packages/rs-dpp/src/data_contract/v1/conversion/cbor.rs new file mode 100644 index 0000000000..08e5e70081 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/conversion/cbor.rs @@ -0,0 +1,98 @@ +use crate::data_contract::conversion::cbor::DataContractCborConversionMethodsV0; +use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; +use crate::util::cbor_value::CborCanonicalMap; + +use crate::data_contract::DataContractV1; +use crate::version::PlatformVersion; +use crate::ProtocolError; +use ciborium::Value as CborValue; +use platform_value::{Identifier, Value}; +use std::convert::TryFrom; + +impl DataContractCborConversionMethodsV0 for DataContractV1 { + // TODO: Do we need to use this? + fn from_cbor_with_id( + cbor_bytes: impl AsRef<[u8]>, + contract_id: Option, + full_validation: bool, + platform_version: &PlatformVersion, + ) -> Result { + let mut data_contract = Self::from_cbor(cbor_bytes, full_validation, platform_version)?; + if let Some(id) = contract_id { + data_contract.id = id; + } + Ok(data_contract) + } + + fn from_cbor( + cbor_bytes: impl AsRef<[u8]>, + full_validation: bool, + platform_version: &PlatformVersion, + ) -> Result { + let data_contract_cbor_value: CborValue = ciborium::de::from_reader(cbor_bytes.as_ref()) + .map_err(|_| { + ProtocolError::DecodingError("unable to decode contract from cbor".to_string()) + })?; + + let data_contract_value: Value = + Value::try_from(data_contract_cbor_value).map_err(ProtocolError::ValueError)?; + + Self::from_value(data_contract_value, full_validation, platform_version) + } + + fn to_cbor(&self, platform_version: &PlatformVersion) -> Result, ProtocolError> { + let value = self.to_value(platform_version)?; + + let mut buf: Vec = Vec::new(); + + ciborium::ser::into_writer(&value, &mut buf) + .map_err(|e| ProtocolError::EncodingError(e.to_string()))?; + + Ok(buf) + } + + // /// Returns Data Contract as a Buffer + // fn to_cbor_buffer(&self) -> Result, ProtocolError> { + // let mut object = self.to_object()?; + // if self.defs.is_none() { + // object.remove(property_names::DEFINITIONS)?; + // } + // object + // .to_map_mut() + // .unwrap() + // .sort_by_lexicographical_byte_ordering_keys_and_inner_maps(); + // + // // we are on version 0 here + // cbor_serializer::serializable_value_to_cbor(&object, Some(0)) + // } + + // TODO: Revisit + fn to_cbor_canonical_map( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + unimplemented!(); + + // let mut contract_cbor_map = CborCanonicalMap::new(); + // + // contract_cbor_map.insert(property_names::ID, self.id.to_buffer().to_vec()); + // contract_cbor_map.insert(property_names::SCHEMA, self.schema.as_str()); + // contract_cbor_map.insert(property_names::VERSION, self.version); + // contract_cbor_map.insert(property_names::OWNER_ID, self.owner_id.to_buffer().to_vec()); + // + // let docs = CborValue::serialized(&self.documents) + // .map_err(|e| ProtocolError::EncodingError(e.to_string()))?; + // + // contract_cbor_map.insert(property_names::DOCUMENTS, docs); + // + // if let Some(_defs) = &self.defs { + // contract_cbor_map.insert( + // property_names::DEFINITIONS, + // CborValue::serialized(&self.defs) + // .map_err(|e| ProtocolError::EncodingError(e.to_string()))?, + // ); + // }; + // + // Ok(contract_cbor_map) + } +} diff --git a/packages/rs-dpp/src/data_contract/v1/conversion/json.rs b/packages/rs-dpp/src/data_contract/v1/conversion/json.rs new file mode 100644 index 0000000000..56478ddb8f --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/conversion/json.rs @@ -0,0 +1,38 @@ +use crate::data_contract::conversion::json::DataContractJsonConversionMethodsV0; +use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; + +use crate::version::PlatformVersion; +use crate::ProtocolError; + +use crate::data_contract::DataContractV1; +use serde_json::Value as JsonValue; +use std::convert::TryInto; + +impl DataContractJsonConversionMethodsV0 for DataContractV1 { + fn from_json( + json_value: JsonValue, + full_validation: bool, + platform_version: &PlatformVersion, + ) -> Result { + Self::from_value(json_value.into(), full_validation, platform_version) + } + + /// Returns Data Contract as a JSON Value + fn to_json(&self, platform_version: &PlatformVersion) -> Result { + self.to_value(platform_version)? + .try_into() + .map_err(ProtocolError::ValueError) + + // TODO: I guess we should convert the binary fields back to base64/base58? + } + + /// Returns Data Contract as a JSON Value that can be used for validation + fn to_validating_json( + &self, + platform_version: &PlatformVersion, + ) -> Result { + self.to_value(platform_version)? + .try_into_validating_json() + .map_err(ProtocolError::ValueError) + } +} diff --git a/packages/rs-dpp/src/data_contract/v1/conversion/mod.rs b/packages/rs-dpp/src/data_contract/v1/conversion/mod.rs new file mode 100644 index 0000000000..eb58a91c43 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/conversion/mod.rs @@ -0,0 +1,8 @@ +#[cfg(feature = "data-contract-cbor-conversion")] +mod cbor; +#[cfg(feature = "data-contract-json-conversion")] +mod json; +#[cfg(feature = "data-contract-value-conversion")] +mod value; + +// TODO: We need from_* / from_*_value / to_* / to_*_value methods for all types: cbor, json, platform_value (value?) diff --git a/packages/rs-dpp/src/data_contract/v1/conversion/value.rs b/packages/rs-dpp/src/data_contract/v1/conversion/value.rs new file mode 100644 index 0000000000..ab8452716c --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/conversion/value.rs @@ -0,0 +1,78 @@ +use crate::data_contract::conversion::value::v0::DataContractValueConversionMethodsV0; + +use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0; +use crate::data_contract::serialized_version::v1::DataContractInSerializationFormatV1; +use crate::data_contract::serialized_version::{property_names, DataContractInSerializationFormat}; +use crate::data_contract::DataContractV1; +use crate::version::PlatformVersion; +use crate::ProtocolError; +use platform_value::{ReplacementType, Value}; +use platform_version::TryFromPlatformVersioned; + +pub const DATA_CONTRACT_IDENTIFIER_FIELDS_V0: [&str; 2] = + [property_names::ID, property_names::OWNER_ID]; + +impl DataContractValueConversionMethodsV0 for DataContractV1 { + fn from_value( + mut value: Value, + full_validation: bool, + platform_version: &PlatformVersion, + ) -> Result { + value.replace_at_paths( + DATA_CONTRACT_IDENTIFIER_FIELDS_V0, + ReplacementType::Identifier, + )?; + let format_version = value.get_str("$format_version")?; + match format_version { + "0" => { + let data_contract_data: DataContractInSerializationFormatV0 = + platform_value::from_value(value).map_err(ProtocolError::ValueError)?; + + DataContractV1::try_from_platform_versioned( + data_contract_data.into(), + full_validation, + &mut vec![], // this is not used in consensus code + platform_version, + ) + } + "1" => { + let data_contract_data: DataContractInSerializationFormatV1 = + platform_value::from_value(value).map_err(ProtocolError::ValueError)?; + + DataContractV1::try_from_platform_versioned( + data_contract_data.into(), + full_validation, + &mut vec![], // this is not used in consensus code + platform_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DataContractV1::from_value".to_string(), + known_versions: vec![0, 1], + received: version + .parse() + .map_err(|_| ProtocolError::Generic("Conversion error".to_string()))?, + }), + } + } + + fn to_value(&self, platform_version: &PlatformVersion) -> Result { + let data_contract_data = + DataContractInSerializationFormat::try_from_platform_versioned(self, platform_version)?; + + let value = + platform_value::to_value(data_contract_data).map_err(ProtocolError::ValueError)?; + + Ok(value) + } + + fn into_value(self, platform_version: &PlatformVersion) -> Result { + let data_contract_data = + DataContractInSerializationFormat::try_from_platform_versioned(self, platform_version)?; + + let value = + platform_value::to_value(data_contract_data).map_err(ProtocolError::ValueError)?; + + Ok(value) + } +} diff --git a/packages/rs-dpp/src/data_contract/v1/data_contract.rs b/packages/rs-dpp/src/data_contract/v1/data_contract.rs new file mode 100644 index 0000000000..60a6527fd0 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/data_contract.rs @@ -0,0 +1,75 @@ +use std::collections::BTreeMap; + +use platform_value::Identifier; +use platform_value::Value; + +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use crate::data_contract::config::DataContractConfig; +use crate::data_contract::document_type::DocumentType; +use crate::data_contract::group::Group; +use crate::data_contract::{ + DefinitionName, DocumentName, GroupContractPosition, TokenContractPosition, +}; +use crate::metadata::Metadata; + +/// `DataContractV1` represents a data contract in a decentralized platform. +/// +/// It contains information about the contract, such as its protocol version, unique identifier, +/// schema, version, and owner identifier. The struct also includes details about the document +/// types, metadata, configuration, and document schemas associated with the contract. +/// +/// Additionally, `DataContractV1` holds definitions for JSON schemas, entropy, and binary properties +/// of the documents. +/// +/// # Changes from `DataContractV0` to `DataContractV1` +/// +/// In `DataContractV1`, two significant features were introduced to enhance contract governance +/// and support token-related operations: +/// +/// 1. **Groups** (`groups: BTreeMap`) +/// - Groups allow for specific multiparty actions on the contract. Each group is defined with a +/// set of members (`Identifier`) and their corresponding member power (`u32`). +/// - Groups facilitate fine-grained access control and decision-making processes by enabling +/// required power thresholds for group actions. +/// - This is particularly useful for contracts where multiple parties are involved in controlling +/// or managing contract-specific features. +/// +/// 2. **Tokens** (`tokens: BTreeMap`) +/// - Tokens introduce configurable token-related functionality within the contract, such as +/// base supply, maximum supply, and manual minting/burning rules. +/// - Token configurations include change control rules, ensuring proper governance for +/// modifying supply limits and token-related settings. +/// - This addition enables contracts to define and manage tokens while ensuring compliance +/// with governance rules (e.g., who can mint or burn tokens). +/// +#[derive(Debug, Clone, PartialEq)] +pub struct DataContractV1 { + /// A unique identifier for the data contract. + /// This field must always present in all versions. + pub id: Identifier, + + /// The version of this data contract. + pub version: u32, + + /// The identifier of the contract owner. + pub owner_id: Identifier, + + /// A mapping of document names to their corresponding document types. + pub document_types: BTreeMap, + + // TODO: Move metadata from here + /// Optional metadata associated with the contract. + pub metadata: Option, + + /// Internal configuration for the contract. + pub config: DataContractConfig, + + /// Shared subschemas to reuse across documents (see $defs) + pub schema_defs: Option>, + + /// Groups that allow for specific multiparty actions on the contract + pub groups: BTreeMap, + + /// The tokens on the contract. + pub tokens: BTreeMap, +} diff --git a/packages/rs-dpp/src/data_contract/v1/methods/mod.rs b/packages/rs-dpp/src/data_contract/v1/methods/mod.rs new file mode 100644 index 0000000000..6bde67a2b1 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/methods/mod.rs @@ -0,0 +1 @@ +mod schema; diff --git a/packages/rs-dpp/src/data_contract/v1/methods/schema.rs b/packages/rs-dpp/src/data_contract/v1/methods/schema.rs new file mode 100644 index 0000000000..901813af16 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/methods/schema.rs @@ -0,0 +1,198 @@ +use crate::data_contract::config::v0::DataContractConfigGettersV0; +use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; +use crate::data_contract::document_type::DocumentType; +use crate::data_contract::schema::DataContractSchemaMethodsV0; +use crate::data_contract::{DataContractV1, DefinitionName, DocumentName}; +use crate::validation::operations::ProtocolValidationOperation; +use crate::ProtocolError; +use platform_value::Value; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +impl DataContractSchemaMethodsV0 for DataContractV1 { + fn set_document_schemas( + &mut self, + schemas: BTreeMap, + defs: Option>, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), ProtocolError> { + self.document_types = DocumentType::create_document_types_from_document_schemas( + self.id, + schemas, + defs.as_ref(), + self.config.documents_keep_history_contract_default(), + self.config.documents_mutable_contract_default(), + self.config.documents_can_be_deleted_contract_default(), + full_validation, + !self.tokens.is_empty(), + validation_operations, + platform_version, + )?; + + Ok(()) + } + + fn set_document_schema( + &mut self, + name: &str, + schema: Value, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), ProtocolError> { + let document_type = DocumentType::try_from_schema( + self.id, + name, + schema, + self.schema_defs.as_ref(), + self.config.documents_keep_history_contract_default(), + self.config.documents_mutable_contract_default(), + self.config.documents_mutable_contract_default(), + full_validation, + validation_operations, + platform_version, + )?; + + self.document_types + .insert(document_type.name().clone(), document_type); + + Ok(()) + } + + fn document_schemas(&self) -> BTreeMap { + self.document_types + .iter() + .map(|(name, document_type)| (name.to_owned(), document_type.schema())) + .collect() + } + + fn schema_defs(&self) -> Option<&BTreeMap> { + self.schema_defs.as_ref() + } + + fn set_schema_defs( + &mut self, + defs: Option>, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), ProtocolError> { + let document_schemas = self + .document_types + .iter() + .map(|(name, document_type)| (name.to_owned(), document_type.schema().to_owned())) + .collect(); + + self.set_document_schemas( + document_schemas, + defs.clone(), + full_validation, + validation_operations, + platform_version, + )?; + + self.schema_defs = defs; + + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::data_contract::config::DataContractConfig; + use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0; + use crate::data_contract::v1::DataContractV1; + use platform_value::{platform_value, Identifier}; + + #[test] + fn should_set_a_new_schema_defs() { + let platform_version = PlatformVersion::latest(); + + let config = DataContractConfig::default_for_version(platform_version) + .expect("should create a default config"); + + let schema = platform_value!({ + "type": "object", + "properties": { + "a": { + "type": "string", + "maxLength": 10, + "position": 0 + } + }, + "additionalProperties": false, + }); + + let serialization_format = DataContractInSerializationFormatV0 { + id: Identifier::random(), + config, + version: 0, + owner_id: Default::default(), + schema_defs: None, + document_schemas: BTreeMap::from([("document_type_name".to_string(), schema.clone())]), + }; + + let mut data_contract = DataContractV1::try_from_platform_versioned( + serialization_format.into(), + true, + &mut vec![], + platform_version, + ) + .expect("should create a contract from serialization format"); + + let defs = platform_value!({ + "test": { + "type": "string", + }, + }); + + let defs_map = Some(defs.into_btree_string_map().expect("should convert to map")); + + data_contract + .set_schema_defs(defs_map.clone(), true, &mut vec![], platform_version) + .expect("should set defs"); + + assert_eq!(defs_map.as_ref(), data_contract.schema_defs()) + } + + fn should_set_empty_schema_defs() { + let platform_version = PlatformVersion::latest(); + + let config = DataContractConfig::default_for_version(platform_version) + .expect("should create a default config"); + + let defs = platform_value!({ + "test": { + "type": "string", + }, + }); + + let defs_map = Some(defs.into_btree_string_map().expect("should convert to map")); + + let serialization_format = DataContractInSerializationFormatV0 { + id: Identifier::random(), + config, + version: 0, + owner_id: Default::default(), + schema_defs: defs_map, + document_schemas: Default::default(), + }; + + let mut data_contract = DataContractV1::try_from_platform_versioned( + serialization_format.into(), + true, + &mut vec![], + platform_version, + ) + .expect("should create a contract from serialization format"); + + data_contract + .set_schema_defs(None, true, &mut vec![], platform_version) + .expect("should set defs"); + + assert_eq!(None, data_contract.schema_defs()) + } +} diff --git a/packages/rs-dpp/src/data_contract/v1/mod.rs b/packages/rs-dpp/src/data_contract/v1/mod.rs new file mode 100644 index 0000000000..c814a35c4b --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/mod.rs @@ -0,0 +1,7 @@ +mod accessors; +mod conversion; +pub mod data_contract; +mod methods; +pub mod serialization; + +pub use data_contract::*; diff --git a/packages/rs-dpp/src/data_contract/v1/serialization/mod.rs b/packages/rs-dpp/src/data_contract/v1/serialization/mod.rs new file mode 100644 index 0000000000..9939a80e85 --- /dev/null +++ b/packages/rs-dpp/src/data_contract/v1/serialization/mod.rs @@ -0,0 +1,194 @@ +use crate::data_contract::config::v0::DataContractConfigGettersV0; +use crate::data_contract::document_type::DocumentType; +use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0; +use crate::data_contract::serialized_version::DataContractInSerializationFormat; +use crate::data_contract::{DataContract, DataContractV1}; +use crate::version::{PlatformVersion, PlatformVersionCurrentVersion}; +use crate::ProtocolError; + +use crate::data_contract::serialized_version::v1::DataContractInSerializationFormatV1; +use crate::validation::operations::ProtocolValidationOperation; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +impl Serialize for DataContractV1 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let data_contract: DataContract = self.clone().into(); + let serialization_format = DataContractInSerializationFormatV1::from(data_contract); + serialization_format.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for DataContractV1 { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let serialization_format = DataContractInSerializationFormat::deserialize(deserializer)?; + let current_version = + PlatformVersion::get_current().map_err(|e| serde::de::Error::custom(e.to_string()))?; + // when deserializing from json/platform_value/cbor we always want to validate (as this is not coming from the state) + DataContractV1::try_from_platform_versioned( + serialization_format, + true, + &mut vec![], + current_version, + ) + .map_err(serde::de::Error::custom) + } +} + +impl DataContractV1 { + pub(in crate::data_contract) fn try_from_platform_versioned( + value: DataContractInSerializationFormat, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + match value { + DataContractInSerializationFormat::V0(serialization_format_v0) => { + let data_contract = DataContractV1::try_from_platform_versioned_v0( + serialization_format_v0, + full_validation, + validation_operations, + platform_version, + )?; + + Ok(data_contract) + } + DataContractInSerializationFormat::V1(serialization_format_v1) => { + let data_contract = DataContractV1::try_from_platform_versioned_v1( + serialization_format_v1, + full_validation, + validation_operations, + platform_version, + )?; + + Ok(data_contract) + } + } + } + + pub(in crate::data_contract) fn try_from_platform_versioned_v0( + data_contract_data: DataContractInSerializationFormatV0, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + let DataContractInSerializationFormatV0 { + id, + config, + version, + owner_id, + document_schemas, + schema_defs, + } = data_contract_data; + + let document_types = DocumentType::create_document_types_from_document_schemas( + id, + document_schemas, + schema_defs.as_ref(), + config.documents_keep_history_contract_default(), + config.documents_mutable_contract_default(), + config.documents_can_be_deleted_contract_default(), + full_validation, + false, + validation_operations, + platform_version, + )?; + + let data_contract = DataContractV1 { + id, + version, + owner_id, + document_types, + metadata: None, + config, + schema_defs, + groups: Default::default(), + tokens: Default::default(), + }; + + Ok(data_contract) + } + + pub(in crate::data_contract) fn try_from_platform_versioned_v1( + data_contract_data: DataContractInSerializationFormatV1, + full_validation: bool, + validation_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + let DataContractInSerializationFormatV1 { + id, + config, + version, + owner_id, + document_schemas, + schema_defs, + groups, + tokens, + } = data_contract_data; + + let document_types = DocumentType::create_document_types_from_document_schemas( + id, + document_schemas, + schema_defs.as_ref(), + config.documents_keep_history_contract_default(), + config.documents_mutable_contract_default(), + config.documents_can_be_deleted_contract_default(), + full_validation, + !tokens.is_empty(), + validation_operations, + platform_version, + )?; + + let data_contract = DataContractV1 { + id, + version, + owner_id, + document_types, + metadata: None, + config, + schema_defs, + groups, + tokens, + }; + + Ok(data_contract) + } +} + +#[cfg(test)] +mod tests { + use crate::data_contract::DataContract; + use crate::identity::accessors::IdentityGettersV0; + use crate::identity::Identity; + use crate::serialization::{ + PlatformDeserializableWithPotentialValidationFromVersionedStructure, + PlatformSerializableWithPlatformVersion, + }; + use crate::tests::fixtures::get_data_contract_fixture; + use crate::version::PlatformVersion; + use platform_version::version::LATEST_PLATFORM_VERSION; + + #[test] + #[cfg(feature = "random-identities")] + fn data_contract_ser_de() { + // V1 of the contract is first present in protocol version 7 + let platform_version = PlatformVersion::get(7).expect("expected protocol version 7"); + let identity = Identity::random_identity(5, Some(5), platform_version) + .expect("expected a random identity"); + let contract = + get_data_contract_fixture(Some(identity.id()), 0, platform_version.protocol_version) + .data_contract_owned(); + let bytes = contract + .serialize_to_bytes_with_platform_version(LATEST_PLATFORM_VERSION) + .expect("expected to serialize"); + let recovered_contract = + DataContract::versioned_deserialize(&bytes, false, platform_version) + .expect("expected to deserialize state transition"); + assert_eq!(contract, recovered_contract); + } +} diff --git a/packages/rs-dpp/src/document/document_factory/mod.rs b/packages/rs-dpp/src/document/document_factory/mod.rs index 75db720fd5..158daf9488 100644 --- a/packages/rs-dpp/src/document/document_factory/mod.rs +++ b/packages/rs-dpp/src/document/document_factory/mod.rs @@ -13,8 +13,9 @@ use crate::document::Document; #[cfg(feature = "extended-document")] use crate::document::ExtendedDocument; #[cfg(feature = "state-transitions")] -use crate::state_transition::documents_batch_transition::{ - document_transition::action_type::DocumentTransitionActionType, DocumentsBatchTransition, +use crate::state_transition::batch_transition::{ + batched_transition::document_transition_action_type::DocumentTransitionActionType, + BatchTransition, }; use crate::util::entropy_generator::EntropyGenerator; pub use v0::DocumentFactoryV0; @@ -120,7 +121,7 @@ impl DocumentFactory { ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce - ) -> Result { + ) -> Result { match self { DocumentFactory::V0(v0) => v0.create_state_transition(documents_iter, nonce_counter), } diff --git a/packages/rs-dpp/src/document/document_factory/v0/mod.rs b/packages/rs-dpp/src/document/document_factory/v0/mod.rs index 58fc96de91..5fa252dc97 100644 --- a/packages/rs-dpp/src/document/document_factory/v0/mod.rs +++ b/packages/rs-dpp/src/document/document_factory/v0/mod.rs @@ -20,18 +20,20 @@ use crate::document::document_methods::DocumentMethodsV0; #[cfg(feature = "extended-document")] use crate::document::{ extended_document::v0::ExtendedDocumentV0, - serialization_traits::DocumentPlatformConversionMethodsV0, ExtendedDocument, + ExtendedDocument, serialization_traits::DocumentPlatformConversionMethodsV0, }; use crate::prelude::{BlockHeight, CoreBlockHeight, TimestampMillis}; #[cfg(feature = "state-transitions")] -use crate::state_transition::documents_batch_transition::{ - document_transition::{ - action_type::DocumentTransitionActionType, DocumentCreateTransition, - DocumentDeleteTransition, DocumentReplaceTransition, DocumentTransition, +use crate::state_transition::batch_transition::{ + batched_transition::{ + document_transition_action_type::DocumentTransitionActionType, DocumentCreateTransition, + DocumentDeleteTransition, DocumentReplaceTransition, }, - DocumentsBatchTransition, DocumentsBatchTransitionV0, + BatchTransition, BatchTransitionV0, }; use itertools::Itertools; +#[cfg(feature = "state-transitions")] +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; const PROPERTY_FEATURE_VERSION: &str = "$version"; const PROPERTY_ENTROPY: &str = "$entropy"; @@ -210,7 +212,7 @@ impl DocumentFactoryV0 { ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce - ) -> Result { + ) -> Result { let platform_version = PlatformVersion::get(self.protocol_version)?; let documents: Vec<( DocumentTransitionActionType, @@ -275,7 +277,7 @@ impl DocumentFactoryV0 { return Err(DocumentError::NoDocumentsSuppliedError.into()); } - Ok(DocumentsBatchTransitionV0 { + Ok(BatchTransitionV0 { owner_id, transitions, user_fee_increase: 0, diff --git a/packages/rs-dpp/src/document/errors.rs b/packages/rs-dpp/src/document/errors.rs index d16ca16f1e..9df0c53b50 100644 --- a/packages/rs-dpp/src/document/errors.rs +++ b/packages/rs-dpp/src/document/errors.rs @@ -6,7 +6,7 @@ use crate::errors::consensus::ConsensusError; use crate::document::accessors::v0::DocumentV0Getters; use crate::document::Document; #[cfg(feature = "state-transitions")] -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; #[derive(Error, Debug)] pub enum DocumentError { diff --git a/packages/rs-dpp/src/document/specialized_document_factory/mod.rs b/packages/rs-dpp/src/document/specialized_document_factory/mod.rs index 8a9c438804..0d7a25b3dc 100644 --- a/packages/rs-dpp/src/document/specialized_document_factory/mod.rs +++ b/packages/rs-dpp/src/document/specialized_document_factory/mod.rs @@ -13,8 +13,9 @@ use crate::document::Document; #[cfg(feature = "extended-document")] use crate::document::ExtendedDocument; #[cfg(feature = "state-transitions")] -use crate::state_transition::documents_batch_transition::{ - document_transition::action_type::DocumentTransitionActionType, DocumentsBatchTransition, +use crate::state_transition::batch_transition::{ + batched_transition::document_transition_action_type::DocumentTransitionActionType, + BatchTransition, }; use crate::util::entropy_generator::EntropyGenerator; pub use v0::SpecializedDocumentFactoryV0; @@ -123,7 +124,7 @@ impl SpecializedDocumentFactory { ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce - ) -> Result { + ) -> Result { match self { SpecializedDocumentFactory::V0(v0) => { v0.create_state_transition(documents_iter, nonce_counter) diff --git a/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs b/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs index e482d3822a..c89c7e3448 100644 --- a/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs +++ b/packages/rs-dpp/src/document/specialized_document_factory/v0/mod.rs @@ -19,18 +19,20 @@ use crate::data_contract::document_type::methods::DocumentTypeV0Methods; #[cfg(feature = "extended-document")] use crate::document::{ extended_document::v0::ExtendedDocumentV0, - serialization_traits::DocumentPlatformConversionMethodsV0, ExtendedDocument, + ExtendedDocument, serialization_traits::DocumentPlatformConversionMethodsV0, }; use crate::prelude::{BlockHeight, CoreBlockHeight, TimestampMillis}; #[cfg(feature = "state-transitions")] -use crate::state_transition::documents_batch_transition::{ - document_transition::{ - action_type::DocumentTransitionActionType, DocumentCreateTransition, - DocumentDeleteTransition, DocumentReplaceTransition, DocumentTransition, +use crate::state_transition::batch_transition::{ + batched_transition::{ + document_transition_action_type::DocumentTransitionActionType, DocumentCreateTransition, + DocumentDeleteTransition, DocumentReplaceTransition, }, - DocumentsBatchTransition, DocumentsBatchTransitionV0, + BatchTransition, BatchTransitionV0, }; use itertools::Itertools; +#[cfg(feature = "state-transitions")] +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; const PROPERTY_FEATURE_VERSION: &str = "$version"; const PROPERTY_ENTROPY: &str = "$entropy"; @@ -218,7 +220,7 @@ impl SpecializedDocumentFactoryV0 { ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce - ) -> Result { + ) -> Result { let platform_version = PlatformVersion::get(self.protocol_version)?; let documents: Vec<( DocumentTransitionActionType, @@ -283,7 +285,7 @@ impl SpecializedDocumentFactoryV0 { return Err(DocumentError::NoDocumentsSuppliedError.into()); } - Ok(DocumentsBatchTransitionV0 { + Ok(BatchTransitionV0 { owner_id, transitions, user_fee_increase: 0, 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 2b24a1e280..e99398b757 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -9,15 +9,18 @@ use crate::consensus::basic::data_contract::InvalidJsonSchemaRefError; use crate::consensus::basic::data_contract::{ ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractHaveNewUniqueIndexError, DataContractImmutablePropertiesUpdateError, - DataContractInvalidIndexDefinitionUpdateError, DataContractUniqueIndicesChangedError, - DuplicateIndexError, DuplicateIndexNameError, IncompatibleDataContractSchemaError, - IncompatibleDocumentTypeSchemaError, IncompatibleRe2PatternError, InvalidCompoundIndexError, - InvalidDataContractIdError, InvalidDataContractVersionError, InvalidDocumentTypeNameError, + DataContractInvalidIndexDefinitionUpdateError, DataContractTokenConfigurationUpdateError, + DataContractUniqueIndicesChangedError, DuplicateIndexError, DuplicateIndexNameError, + IncompatibleDataContractSchemaError, IncompatibleDocumentTypeSchemaError, + IncompatibleRe2PatternError, InvalidCompoundIndexError, InvalidDataContractIdError, + InvalidDataContractVersionError, InvalidDocumentTypeNameError, InvalidDocumentTypeRequiredSecurityLevelError, InvalidIndexPropertyTypeError, - InvalidIndexedPropertyConstraintError, SystemPropertyIndexAlreadyPresentError, - UndefinedIndexPropertyError, UniqueIndicesLimitReachedError, - UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, - UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError, + InvalidIndexedPropertyConstraintError, InvalidTokenBaseSupplyError, + NonContiguousContractGroupPositionsError, NonContiguousContractTokenPositionsError, + SystemPropertyIndexAlreadyPresentError, UndefinedIndexPropertyError, + UniqueIndicesLimitReachedError, UnknownDocumentCreationRestrictionModeError, + UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, + UnknownTransferableTypeError, }; use crate::consensus::basic::decode::{ ProtocolVersionParsingError, SerializedObjectParsingError, VersionError, @@ -64,7 +67,13 @@ use crate::consensus::basic::{ }; use crate::consensus::ConsensusError; +use crate::consensus::basic::group::GroupActionNotAllowedOnTransitionError; use crate::consensus::basic::overflow_error::OverflowError; +use crate::consensus::basic::token::{ + ChoosingTokenMintRecipientNotAllowedError, ContractHasNoTokensError, + DestinationIdentityForTokenMintingNotSetError, InvalidActionIdError, InvalidGroupPositionError, + InvalidTokenIdError, InvalidTokenPositionError, TokenTransferToOurselfError, +}; use crate::consensus::basic::unsupported_version_error::UnsupportedVersionError; use crate::consensus::basic::value_error::ValueError; #[cfg(feature = "json-schema-validation")] @@ -402,6 +411,45 @@ pub enum BasicError { #[error(transparent)] ContestedDocumentsTemporarilyNotAllowedError(ContestedDocumentsTemporarilyNotAllowedError), + + #[error(transparent)] + DataContractTokenConfigurationUpdateError(DataContractTokenConfigurationUpdateError), + + #[error(transparent)] + NonContiguousContractTokenPositionsError(NonContiguousContractTokenPositionsError), + + #[error(transparent)] + NonContiguousContractGroupPositionsError(NonContiguousContractGroupPositionsError), + + #[error(transparent)] + InvalidTokenBaseSupplyError(InvalidTokenBaseSupplyError), + + #[error(transparent)] + InvalidTokenIdError(InvalidTokenIdError), + + #[error(transparent)] + InvalidTokenPositionError(InvalidTokenPositionError), + + #[error(transparent)] + TokenTransferToOurselfError(TokenTransferToOurselfError), + + #[error(transparent)] + ContractHasNoTokensError(ContractHasNoTokensError), + + #[error(transparent)] + InvalidGroupPositionError(InvalidGroupPositionError), + + #[error(transparent)] + InvalidActionIdError(InvalidActionIdError), + + #[error(transparent)] + DestinationIdentityForTokenMintingNotSetError(DestinationIdentityForTokenMintingNotSetError), + + #[error(transparent)] + ChoosingTokenMintRecipientNotAllowedError(ChoosingTokenMintRecipientNotAllowedError), + + #[error(transparent)] + GroupActionNotAllowedOnTransitionError(GroupActionNotAllowedOnTransitionError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/data_contract_token_configuration_update_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/data_contract_token_configuration_update_error.rs new file mode 100644 index 0000000000..a367fb8ad2 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/data_contract_token_configuration_update_error.rs @@ -0,0 +1,63 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +use crate::data_contract::associated_token::token_configuration::TokenConfiguration; +use bincode::{Decode, Encode}; + +#[derive( + Error, Debug, Clone, PartialEq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Forbidden operation '{operation}' on '{field_path}', old config is {old_config}, new config is {new_config}")] +#[platform_serialize(unversioned)] +pub struct DataContractTokenConfigurationUpdateError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + operation: String, + field_path: String, + old_config: TokenConfiguration, + new_config: TokenConfiguration, +} + +impl DataContractTokenConfigurationUpdateError { + pub fn new( + operation: String, + field_path: String, + old_config: TokenConfiguration, + new_config: TokenConfiguration, + ) -> Self { + Self { + operation, + field_path, + old_config, + new_config, + } + } + + pub fn operation(&self) -> String { + self.operation.clone() + } + + pub fn field_path(&self) -> String { + self.field_path.clone() + } + + pub fn old_config(&self) -> TokenConfiguration { + self.old_config.clone() + } + + pub fn new_config(&self) -> TokenConfiguration { + self.new_config.clone() + } +} + +impl From for ConsensusError { + fn from(err: DataContractTokenConfigurationUpdateError) -> Self { + Self::BasicError(BasicError::DataContractTokenConfigurationUpdateError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/invalid_token_base_supply_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/invalid_token_base_supply_error.rs new file mode 100644 index 0000000000..738be8b222 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/invalid_token_base_supply_error.rs @@ -0,0 +1,41 @@ +use crate::consensus::basic::BasicError; +use crate::errors::ProtocolError; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +use crate::consensus::ConsensusError; + +use bincode::{Decode, Encode}; +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Invalid token base supply. Given base supply: {}, Max allowed base supply: {}", + base_supply, + i64::MAX +)] +#[platform_serialize(unversioned)] +pub struct InvalidTokenBaseSupplyError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + base_supply: u64, +} + +impl InvalidTokenBaseSupplyError { + pub fn new(base_supply: u64) -> Self { + Self { base_supply } + } + + pub fn base_supply(&self) -> u64 { + self.base_supply + } +} + +impl From for ConsensusError { + fn from(err: InvalidTokenBaseSupplyError) -> Self { + Self::BasicError(BasicError::InvalidTokenBaseSupplyError(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 9e7bedab0d..2fc29ce57f 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 @@ -4,6 +4,7 @@ mod data_contract_have_new_unique_index_error; mod data_contract_immutable_properties_update_error; mod data_contract_invalid_index_definition_update_error; pub mod data_contract_max_depth_exceed_error; +mod data_contract_token_configuration_update_error; mod data_contract_unique_indices_changed_error; mod document_types_are_missing_error; mod duplicate_index_error; @@ -20,6 +21,9 @@ mod invalid_index_property_type_error; mod invalid_indexed_property_constraint_error; #[cfg(feature = "json-schema-validation")] mod invalid_json_schema_ref_error; +mod invalid_token_base_supply_error; +mod non_contiguous_contract_group_positions_error; +mod non_contiguous_contract_token_positions_error; mod system_property_index_already_present_error; mod undefined_index_property_error; mod unique_indices_limit_reached_error; @@ -32,6 +36,7 @@ mod unknown_transferable_type_error; pub use data_contract_have_new_unique_index_error::*; pub use data_contract_immutable_properties_update_error::*; pub use data_contract_invalid_index_definition_update_error::*; +pub use data_contract_token_configuration_update_error::*; pub use data_contract_unique_indices_changed_error::*; pub use document_types_are_missing_error::*; pub use duplicate_index_error::*; @@ -55,6 +60,9 @@ pub use contested_unique_index_on_mutable_document_type_error::*; pub use contested_unique_index_with_unique_index_error::*; pub use incompatible_document_type_schema_error::*; pub use invalid_document_type_name_error::*; +pub use invalid_token_base_supply_error::*; +pub use non_contiguous_contract_group_positions_error::*; +pub use non_contiguous_contract_token_positions_error::*; pub use unknown_document_creation_restriction_mode_error::*; pub use unknown_security_level_error::*; pub use unknown_storage_key_requirements_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_group_positions_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_group_positions_error.rs new file mode 100644 index 0000000000..3409e866f8 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_group_positions_error.rs @@ -0,0 +1,52 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::GroupContractPosition; +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( + "Contract Group Positions are not contiguous. Missing position: {}, Followed position: {}", + missing_position, + followed_position +)] +#[platform_serialize(unversioned)] +pub struct NonContiguousContractGroupPositionsError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + missing_position: GroupContractPosition, + followed_position: GroupContractPosition, +} + +impl NonContiguousContractGroupPositionsError { + pub fn new( + missing_position: GroupContractPosition, + followed_position: GroupContractPosition, + ) -> Self { + Self { + missing_position, + followed_position, + } + } + + pub fn missing_position(&self) -> u16 { + self.missing_position + } + + pub fn followed_position(&self) -> u16 { + self.followed_position + } +} + +impl From for ConsensusError { + fn from(err: NonContiguousContractGroupPositionsError) -> Self { + Self::BasicError(BasicError::NonContiguousContractGroupPositionsError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_token_positions_error.rs b/packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_token_positions_error.rs new file mode 100644 index 0000000000..2875f2bb42 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/data_contract/non_contiguous_contract_token_positions_error.rs @@ -0,0 +1,52 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::TokenContractPosition; +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( + "Contract Token Positions are not contiguous. Missing position: {}, Followed position: {}", + missing_position, + followed_position +)] +#[platform_serialize(unversioned)] +pub struct NonContiguousContractTokenPositionsError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + missing_position: TokenContractPosition, + followed_position: TokenContractPosition, +} + +impl NonContiguousContractTokenPositionsError { + pub fn new( + missing_position: TokenContractPosition, + followed_position: TokenContractPosition, + ) -> Self { + Self { + missing_position, + followed_position, + } + } + + pub fn missing_position(&self) -> u16 { + self.missing_position + } + + pub fn followed_position(&self) -> u16 { + self.followed_position + } +} + +impl From for ConsensusError { + fn from(err: NonContiguousContractTokenPositionsError) -> Self { + Self::BasicError(BasicError::NonContiguousContractTokenPositionsError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/group/group_action_not_allowed_on_transition_error.rs b/packages/rs-dpp/src/errors/consensus/basic/group/group_action_not_allowed_on_transition_error.rs new file mode 100644 index 0000000000..8f2862fa9a --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/group/group_action_not_allowed_on_transition_error.rs @@ -0,0 +1,31 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::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 action is not allowed during transition: {}", transition_type)] +#[platform_serialize(unversioned)] +pub struct GroupActionNotAllowedOnTransitionError { + transition_type: String, +} + +impl GroupActionNotAllowedOnTransitionError { + pub fn new(transition_type: String) -> Self { + Self { transition_type } + } + + pub fn transition_type(&self) -> &str { + &self.transition_type + } +} + +impl From for ConsensusError { + fn from(err: GroupActionNotAllowedOnTransitionError) -> Self { + Self::BasicError(BasicError::GroupActionNotAllowedOnTransitionError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/group/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/group/mod.rs new file mode 100644 index 0000000000..32c6ce2d35 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/group/mod.rs @@ -0,0 +1,3 @@ +mod group_action_not_allowed_on_transition_error; + +pub use group_action_not_allowed_on_transition_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_is_not_found_error.rs b/packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_is_not_found_error.rs index 61aaa959d2..b4d39d261c 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_is_not_found_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/identity/identity_asset_lock_transaction_is_not_found_error.rs @@ -44,15 +44,3 @@ impl From for ConsensusError { Self::BasicError(BasicError::IdentityAssetLockTransactionIsNotFoundError(err)) } } - -#[cfg(test)] -mod test { - use crate::consensus::basic::identity::IdentityAssetLockTransactionIsNotFoundError; - - #[test] - pub fn test_message() { - let error = IdentityAssetLockTransactionIsNotFoundError::new([1; 32]); - - println!("{}", error); - } -} diff --git a/packages/rs-dpp/src/errors/consensus/basic/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/mod.rs index b96be4629b..b05ec735e6 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/mod.rs @@ -9,9 +9,11 @@ pub mod decode; pub mod document; pub mod identity; pub mod incompatible_protocol_version_error; +pub mod token; pub mod unsupported_protocol_version_error; pub mod basic_error; +pub mod group; pub mod invalid_identifier_error; #[cfg(feature = "json-schema-validation")] pub mod json_schema_compilation_error; diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/choosing_token_mint_recipient_not_allowed_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/choosing_token_mint_recipient_not_allowed_error.rs new file mode 100644 index 0000000000..9d5f2dfc90 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/choosing_token_mint_recipient_not_allowed_error.rs @@ -0,0 +1,31 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::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("Choosing token mint recipient not allowed for token {}", token_id)] +#[platform_serialize(unversioned)] +pub struct ChoosingTokenMintRecipientNotAllowedError { + token_id: Identifier, +} + +impl ChoosingTokenMintRecipientNotAllowedError { + pub fn new(token_id: Identifier) -> Self { + Self { token_id } + } + pub fn token_id(&self) -> Identifier { + self.token_id + } +} + +impl From for ConsensusError { + fn from(err: ChoosingTokenMintRecipientNotAllowedError) -> Self { + Self::BasicError(BasicError::ChoosingTokenMintRecipientNotAllowedError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/contract_has_no_tokens_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/contract_has_no_tokens_error.rs new file mode 100644 index 0000000000..3fc49a2600 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/contract_has_no_tokens_error.rs @@ -0,0 +1,31 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::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("Contract {} has no tokens", contract_id)] +#[platform_serialize(unversioned)] +pub struct ContractHasNoTokensError { + contract_id: Identifier, +} + +impl ContractHasNoTokensError { + pub fn new(contract_id: Identifier) -> Self { + Self { contract_id } + } + pub fn contract_id(&self) -> Identifier { + self.contract_id + } +} + +impl From for ConsensusError { + fn from(err: ContractHasNoTokensError) -> Self { + Self::BasicError(BasicError::ContractHasNoTokensError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/destination_identity_for_token_minting_not_set_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/destination_identity_for_token_minting_not_set_error.rs new file mode 100644 index 0000000000..7136a46e66 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/destination_identity_for_token_minting_not_set_error.rs @@ -0,0 +1,33 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::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("Destination identity for minting not set for token {}", token_id)] +#[platform_serialize(unversioned)] +pub struct DestinationIdentityForTokenMintingNotSetError { + token_id: Identifier, +} + +impl DestinationIdentityForTokenMintingNotSetError { + pub fn new(token_id: Identifier) -> Self { + Self { token_id } + } + pub fn token_id(&self) -> Identifier { + self.token_id + } +} + +impl From for ConsensusError { + fn from(err: DestinationIdentityForTokenMintingNotSetError) -> Self { + Self::BasicError(BasicError::DestinationIdentityForTokenMintingNotSetError( + err, + )) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/invalid_action_id_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_action_id_error.rs new file mode 100644 index 0000000000..51587ab392 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_action_id_error.rs @@ -0,0 +1,43 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::prelude::Identifier; +use crate::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( + "Invalid action id {}, expected {}", + invalid_action_id, + expected_action_id +)] +#[platform_serialize(unversioned)] +pub struct InvalidActionIdError { + expected_action_id: Identifier, + invalid_action_id: Identifier, +} + +impl InvalidActionIdError { + pub fn new(expected_action_id: Identifier, invalid_action_id: Identifier) -> Self { + Self { + expected_action_id, + invalid_action_id, + } + } + + pub fn expected_action_id(&self) -> Identifier { + self.expected_action_id + } + + pub fn invalid_action_id(&self) -> Identifier { + self.invalid_action_id + } +} + +impl From for ConsensusError { + fn from(err: InvalidActionIdError) -> Self { + Self::BasicError(BasicError::InvalidActionIdError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/invalid_group_position_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_group_position_error.rs new file mode 100644 index 0000000000..8464f1064a --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_group_position_error.rs @@ -0,0 +1,47 @@ +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; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Invalid group position {}, expected {}", + invalid_group_position, + expected_group_position +)] +#[platform_serialize(unversioned)] +pub struct InvalidGroupPositionError { + expected_group_position: GroupContractPosition, + invalid_group_position: GroupContractPosition, +} + +impl InvalidGroupPositionError { + pub fn new( + expected_group_position: GroupContractPosition, + invalid_group_position: GroupContractPosition, + ) -> Self { + Self { + expected_group_position, + invalid_group_position, + } + } + + pub fn expected_group_position(&self) -> GroupContractPosition { + self.expected_group_position + } + + pub fn invalid_group_position(&self) -> GroupContractPosition { + self.invalid_group_position + } +} + +impl From for ConsensusError { + fn from(err: InvalidGroupPositionError) -> Self { + Self::BasicError(BasicError::InvalidGroupPositionError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_id_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_id_error.rs new file mode 100644 index 0000000000..635f126158 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_id_error.rs @@ -0,0 +1,43 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::prelude::Identifier; +use crate::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( + "Invalid token id {}, expected {}", + invalid_token_id, + expected_token_id +)] +#[platform_serialize(unversioned)] +pub struct InvalidTokenIdError { + expected_token_id: Identifier, + invalid_token_id: Identifier, +} + +impl InvalidTokenIdError { + pub fn new(expected_token_id: Identifier, invalid_token_id: Identifier) -> Self { + Self { + expected_token_id, + invalid_token_id, + } + } + + pub fn expected_token_id(&self) -> Identifier { + self.expected_token_id + } + + pub fn invalid_token_id(&self) -> Identifier { + self.invalid_token_id + } +} + +impl From for ConsensusError { + fn from(err: InvalidTokenIdError) -> Self { + Self::BasicError(BasicError::InvalidTokenIdError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_position_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_position_error.rs new file mode 100644 index 0000000000..ac157f4193 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/invalid_token_position_error.rs @@ -0,0 +1,47 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::data_contract::TokenContractPosition; +use crate::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( + "Invalid token position {}, max {}", + invalid_token_position, + max_token_position +)] +#[platform_serialize(unversioned)] +pub struct InvalidTokenPositionError { + max_token_position: TokenContractPosition, + invalid_token_position: TokenContractPosition, +} + +impl InvalidTokenPositionError { + pub fn new( + max_token_position: TokenContractPosition, + invalid_token_position: TokenContractPosition, + ) -> Self { + Self { + max_token_position, + invalid_token_position, + } + } + + pub fn max_token_position(&self) -> TokenContractPosition { + self.max_token_position + } + + pub fn invalid_token_position(&self) -> TokenContractPosition { + self.invalid_token_position + } +} + +impl From for ConsensusError { + fn from(err: InvalidTokenPositionError) -> Self { + Self::BasicError(BasicError::InvalidTokenPositionError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs new file mode 100644 index 0000000000..efdcadc77a --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/mod.rs @@ -0,0 +1,17 @@ +mod choosing_token_mint_recipient_not_allowed_error; +mod contract_has_no_tokens_error; +mod destination_identity_for_token_minting_not_set_error; +mod invalid_action_id_error; +mod invalid_group_position_error; +mod invalid_token_id_error; +mod invalid_token_position_error; +mod token_transfer_to_ourselves_error; + +pub use choosing_token_mint_recipient_not_allowed_error::*; +pub use contract_has_no_tokens_error::*; +pub use destination_identity_for_token_minting_not_set_error::*; +pub use invalid_action_id_error::*; +pub use invalid_group_position_error::*; +pub use invalid_token_id_error::*; +pub use invalid_token_position_error::*; +pub use token_transfer_to_ourselves_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/token/token_transfer_to_ourselves_error.rs b/packages/rs-dpp/src/errors/consensus/basic/token/token_transfer_to_ourselves_error.rs new file mode 100644 index 0000000000..dbd1ee747c --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/token/token_transfer_to_ourselves_error.rs @@ -0,0 +1,44 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::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( + "Token transfer to the same identity is not allowed. Token ID: {}, Identity ID: {}", + token_id, + identity_id +)] +#[platform_serialize(unversioned)] +pub struct TokenTransferToOurselfError { + token_id: Identifier, + identity_id: Identifier, +} + +impl TokenTransferToOurselfError { + pub fn new(token_id: Identifier, identity_id: Identifier) -> Self { + Self { + token_id, + identity_id, + } + } + + pub fn token_id(&self) -> &Identifier { + &self.token_id + } + + pub fn identity_id(&self) -> &Identifier { + &self.identity_id + } +} + +impl From for ConsensusError { + fn from(err: TokenTransferToOurselfError) -> Self { + Self::BasicError(BasicError::TokenTransferToOurselfError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index b238f55c02..56f38cfaa2 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -98,8 +98,12 @@ impl ErrorWithCode for BasicError { Self::ContractError(DataContractError::RegexError(_)) => 10247, Self::ContestedUniqueIndexOnMutableDocumentTypeError(_) => 10248, Self::ContestedUniqueIndexWithUniqueIndexError(_) => 10249, + Self::DataContractTokenConfigurationUpdateError { .. } => 10250, + Self::InvalidTokenBaseSupplyError(_) => 10251, + Self::NonContiguousContractGroupPositionsError(_) => 10252, + Self::NonContiguousContractTokenPositionsError(_) => 10253, - // Document Errors: 10400-10499 + // Document Errors: 10400-10449 Self::DataContractNotPresentError { .. } => 10400, Self::DuplicateDocumentTransitionsWithIdsError { .. } => 10401, Self::DuplicateDocumentTransitionsWithIndicesError { .. } => 10402, @@ -120,6 +124,16 @@ impl ErrorWithCode for BasicError { Self::DocumentFieldMaxSizeExceededError(_) => 10417, Self::ContestedDocumentsTemporarilyNotAllowedError(_) => 10418, + // 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, + // Identity Errors: 10500-10599 Self::DuplicatedIdentityPublicKeyBasicError(_) => 10500, Self::DuplicatedIdentityPublicKeyIdBasicError(_) => 10501, @@ -162,6 +176,7 @@ impl ErrorWithCode for BasicError { // General Errors 10700-10799 Self::OverflowError(_) => 10700, + Self::GroupActionNotAllowedOnTransitionError(_) => 10701, } } } @@ -201,7 +216,7 @@ impl ErrorWithCode for StateError { Self::DataContractIsReadonlyError { .. } => 40001, Self::DataContractConfigUpdateError { .. } => 40002, - // Document Errors: 40100-40199 + // Document Errors: 40100-40149 Self::DocumentAlreadyPresentError { .. } => 40100, Self::DocumentNotFoundError { .. } => 40101, Self::DocumentOwnerIdMismatchError { .. } => 40102, @@ -218,6 +233,12 @@ impl ErrorWithCode for StateError { Self::DocumentContestDocumentWithSameIdAlreadyPresentError(_) => 40113, Self::DocumentContestNotPaidForError(_) => 40114, + // Token errors: 40150-40199 + Self::IdentityDoesNotHaveEnoughTokenBalanceError(_) => 40150, + Self::UnauthorizedTokenActionError(_) => 40151, + Self::IdentityTokenAccountFrozenError(_) => 40152, + Self::IdentityTokenAccountNotFrozenError(_) => 40153, + // Identity Errors: 40200-40299 Self::IdentityAlreadyExistsError(_) => 40200, Self::IdentityPublicKeyIsReadOnlyError { .. } => 40201, @@ -235,6 +256,7 @@ impl ErrorWithCode for StateError { Self::DataContractUpdatePermissionError(_) => 40213, Self::MissingTransferKeyError(_) => 40214, Self::NoTransferKeyForCoreWithdrawalAvailableError(_) => 40215, + Self::RecipientIdentityDoesNotExistError(_) => 40216, // Voting Errors: 40300-40399 Self::MasternodeNotFoundError(_) => 40300, @@ -252,6 +274,12 @@ impl ErrorWithCode for StateError { // Data trigger errors: 40500-40799 #[cfg(feature = "state-transition-validation")] Self::DataTriggerError(ref e) => e.code(), + + // Group errors: 40800-40899 + Self::IdentityNotMemberOfGroupError(_) => 40800, + Self::GroupActionDoesNotExistError(_) => 40801, + Self::GroupActionAlreadyCompletedError(_) => 40802, + Self::GroupActionAlreadySignedByIdentityError(_) => 40803, } } } diff --git a/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs b/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs index a753c9ccd6..e43de44458 100644 --- a/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/data_trigger/mod.rs @@ -4,7 +4,7 @@ use crate::consensus::state::data_trigger::data_trigger_invalid_result_error::Da use crate::consensus::state::state_error::StateError; use crate::consensus::ConsensusError; use crate::errors::ProtocolError; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; +use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use thiserror::Error; diff --git a/packages/rs-dpp/src/errors/consensus/state/group/group_action_already_completed_error.rs b/packages/rs-dpp/src/errors/consensus/state/group/group_action_already_completed_error.rs new file mode 100644 index 0000000000..2d700d72a3 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/group/group_action_already_completed_error.rs @@ -0,0 +1,55 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::data_contract::GroupContractPosition; +use crate::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( +"Group action has already been completed for data contract {} at group position {} with action ID {}", + data_contract_id, + group_contract_position, + action_id +)] +#[platform_serialize(unversioned)] +pub struct GroupActionAlreadyCompletedError { + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, +} + +impl GroupActionAlreadyCompletedError { + pub fn new( + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + ) -> Self { + Self { + data_contract_id, + group_contract_position, + action_id, + } + } + + pub fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + pub fn group_contract_position(&self) -> &GroupContractPosition { + &self.group_contract_position + } + + pub fn action_id(&self) -> Identifier { + self.action_id + } +} + +impl From for ConsensusError { + fn from(err: GroupActionAlreadyCompletedError) -> Self { + Self::StateError(StateError::GroupActionAlreadyCompletedError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/group/group_action_already_signed_by_identity_error.rs b/packages/rs-dpp/src/errors/consensus/state/group/group_action_already_signed_by_identity_error.rs new file mode 100644 index 0000000000..1fcdbf0419 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/group/group_action_already_signed_by_identity_error.rs @@ -0,0 +1,64 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::data_contract::GroupContractPosition; +use crate::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( +"Group action with action ID {} has already been signed by identity {} for data contract {} at group position {}", + action_id, + identity_id, + data_contract_id, + group_contract_position +)] +#[platform_serialize(unversioned)] +pub struct GroupActionAlreadySignedByIdentityError { + identity_id: Identifier, + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, +} + +impl GroupActionAlreadySignedByIdentityError { + pub fn new( + identity_id: Identifier, + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + ) -> Self { + Self { + identity_id, + data_contract_id, + group_contract_position, + action_id, + } + } + + pub fn identity_id(&self) -> Identifier { + self.identity_id + } + + pub fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + pub fn group_contract_position(&self) -> GroupContractPosition { + self.group_contract_position + } + + pub fn action_id(&self) -> Identifier { + self.action_id + } +} + +impl From for ConsensusError { + fn from(err: GroupActionAlreadySignedByIdentityError) -> Self { + Self::StateError(StateError::GroupActionAlreadySignedByIdentityError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/group/group_action_does_not_exist_error.rs b/packages/rs-dpp/src/errors/consensus/state/group/group_action_does_not_exist_error.rs new file mode 100644 index 0000000000..c57af3cc4d --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/group/group_action_does_not_exist_error.rs @@ -0,0 +1,56 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::data_contract::GroupContractPosition; +use crate::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( + "Group action does not exist for data contract {} at group position {} with action ID {}", + data_contract_id, + group_contract_position, + action_id +)] +#[platform_serialize(unversioned)] +pub struct GroupActionDoesNotExistError { + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, +} + +impl GroupActionDoesNotExistError { + pub fn new( + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + ) -> Self { + Self { + data_contract_id, + group_contract_position, + action_id, + } + } + + pub fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + pub fn group_contract_position(&self) -> &GroupContractPosition { + &self.group_contract_position + } + + pub fn action_id(&self) -> Identifier { + self.action_id + } +} + +impl From for ConsensusError { + fn from(err: GroupActionDoesNotExistError) -> Self { + Self::StateError(StateError::GroupActionDoesNotExistError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/group/identity_not_member_of_group_error.rs b/packages/rs-dpp/src/errors/consensus/state/group/identity_not_member_of_group_error.rs new file mode 100644 index 0000000000..afd5bf06ff --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/group/identity_not_member_of_group_error.rs @@ -0,0 +1,56 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::data_contract::GroupContractPosition; +use crate::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( + "Identity {} is not a member of the group for data contract {} at position {}", + identity_id, + data_contract_id, + group_contract_position +)] +#[platform_serialize(unversioned)] +pub struct IdentityNotMemberOfGroupError { + identity_id: Identifier, + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, +} + +impl IdentityNotMemberOfGroupError { + pub fn new( + identity_id: Identifier, + data_contract_id: Identifier, + group_contract_position: GroupContractPosition, + ) -> Self { + Self { + identity_id, + data_contract_id, + group_contract_position, + } + } + + pub fn identity_id(&self) -> &Identifier { + &self.identity_id + } + + pub fn data_contract_id(&self) -> &Identifier { + &self.data_contract_id + } + + pub fn group_contract_position(&self) -> GroupContractPosition { + self.group_contract_position + } +} + +impl From for ConsensusError { + fn from(err: IdentityNotMemberOfGroupError) -> Self { + Self::StateError(StateError::IdentityNotMemberOfGroupError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/group/mod.rs b/packages/rs-dpp/src/errors/consensus/state/group/mod.rs new file mode 100644 index 0000000000..133ee7e1a5 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/group/mod.rs @@ -0,0 +1,9 @@ +mod group_action_already_completed_error; +mod group_action_already_signed_by_identity_error; +mod group_action_does_not_exist_error; +mod identity_not_member_of_group_error; + +pub use group_action_already_completed_error::*; +pub use group_action_already_signed_by_identity_error::*; +pub use group_action_does_not_exist_error::*; +pub use identity_not_member_of_group_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/identity/mod.rs b/packages/rs-dpp/src/errors/consensus/state/identity/mod.rs index 35e6f7f79a..072bbda4ac 100644 --- a/packages/rs-dpp/src/errors/consensus/state/identity/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/identity/mod.rs @@ -16,3 +16,6 @@ pub mod max_identity_public_key_limit_reached_error; pub mod missing_identity_public_key_ids_error; pub mod missing_transfer_key_error; pub mod no_transfer_key_for_core_withdrawal_available_error; + +mod recipient_identity_does_not_exist_error; +pub use recipient_identity_does_not_exist_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/identity/recipient_identity_does_not_exist_error.rs b/packages/rs-dpp/src/errors/consensus/state/identity/recipient_identity_does_not_exist_error.rs new file mode 100644 index 0000000000..dc6a838f76 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/identity/recipient_identity_does_not_exist_error.rs @@ -0,0 +1,31 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::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("Recipient identity {} does not exist", recipient_id)] +#[platform_serialize(unversioned)] +pub struct RecipientIdentityDoesNotExistError { + recipient_id: Identifier, +} + +impl RecipientIdentityDoesNotExistError { + pub fn new(recipient_id: Identifier) -> Self { + Self { recipient_id } + } + pub fn recipient_id(&self) -> Identifier { + self.recipient_id + } +} + +impl From for ConsensusError { + fn from(err: RecipientIdentityDoesNotExistError) -> Self { + Self::StateError(StateError::RecipientIdentityDoesNotExistError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/mod.rs b/packages/rs-dpp/src/errors/consensus/state/mod.rs index 118ca4b10c..ee10b800d1 100644 --- a/packages/rs-dpp/src/errors/consensus/state/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/mod.rs @@ -2,7 +2,9 @@ pub mod data_contract; #[cfg(feature = "state-transition-validation")] pub mod data_trigger; pub mod document; +pub mod group; pub mod identity; pub mod prefunded_specialized_balances; pub mod state_error; +pub mod token; pub mod voting; 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 8b0ac2b26b..9dc0a2938b 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -23,9 +23,7 @@ use crate::consensus::state::identity::invalid_identity_public_key_id_error::Inv use crate::consensus::state::identity::invalid_identity_revision_error::InvalidIdentityRevisionError; use crate::consensus::state::identity::max_identity_public_key_limit_reached_error::MaxIdentityPublicKeyLimitReachedError; use crate::consensus::state::identity::missing_identity_public_key_ids_error::MissingIdentityPublicKeyIdsError; -use crate::consensus::state::identity::{ - IdentityAlreadyExistsError, IdentityInsufficientBalanceError, -}; +use crate::consensus::state::identity::{IdentityAlreadyExistsError, IdentityInsufficientBalanceError, RecipientIdentityDoesNotExistError}; use crate::consensus::ConsensusError; use crate::consensus::state::data_contract::data_contract_update_permission_error::DataContractUpdatePermissionError; use crate::consensus::state::data_contract::document_type_update_error::DocumentTypeUpdateError; @@ -36,12 +34,14 @@ use crate::consensus::state::document::document_contest_not_joinable_error::Docu use crate::consensus::state::document::document_contest_not_paid_for_error::DocumentContestNotPaidForError; use crate::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; use crate::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; +use crate::consensus::state::group::{GroupActionAlreadyCompletedError, GroupActionAlreadySignedByIdentityError, GroupActionDoesNotExistError, IdentityNotMemberOfGroupError}; use crate::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; use crate::consensus::state::identity::invalid_identity_contract_nonce_error::InvalidIdentityNonceError; use crate::consensus::state::identity::missing_transfer_key_error::MissingTransferKeyError; use crate::consensus::state::identity::no_transfer_key_for_core_withdrawal_available_error::NoTransferKeyForCoreWithdrawalAvailableError; use crate::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_insufficient_error::PrefundedSpecializedBalanceInsufficientError; use crate::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError; +use crate::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError, IdentityTokenAccountNotFrozenError, UnauthorizedTokenActionError}; use crate::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError; use crate::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError; use crate::consensus::state::voting::masternode_not_found_error::MasternodeNotFoundError; @@ -199,6 +199,33 @@ pub enum StateError { #[error(transparent)] MasternodeVoteAlreadyPresentError(MasternodeVoteAlreadyPresentError), + + #[error(transparent)] + RecipientIdentityDoesNotExistError(RecipientIdentityDoesNotExistError), + + #[error(transparent)] + IdentityDoesNotHaveEnoughTokenBalanceError(IdentityDoesNotHaveEnoughTokenBalanceError), + + #[error(transparent)] + UnauthorizedTokenActionError(UnauthorizedTokenActionError), + + #[error(transparent)] + IdentityTokenAccountFrozenError(IdentityTokenAccountFrozenError), + + #[error(transparent)] + IdentityTokenAccountNotFrozenError(IdentityTokenAccountNotFrozenError), + + #[error(transparent)] + IdentityNotMemberOfGroupError(IdentityNotMemberOfGroupError), + + #[error(transparent)] + GroupActionDoesNotExistError(GroupActionDoesNotExistError), + + #[error(transparent)] + GroupActionAlreadyCompletedError(GroupActionAlreadyCompletedError), + + #[error(transparent)] + GroupActionAlreadySignedByIdentityError(GroupActionAlreadySignedByIdentityError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/state/token/identity_does_not_have_enough_token_balance_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/identity_does_not_have_enough_token_balance_error.rs new file mode 100644 index 0000000000..ba1c5b7fd6 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/identity_does_not_have_enough_token_balance_error.rs @@ -0,0 +1,70 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::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( + "Identity {} does not have enough balance for token {}: required {}, actual {}, action: {}", + identity_id, + token_id, + required_balance, + actual_balance, + action +)] +#[platform_serialize(unversioned)] +pub struct IdentityDoesNotHaveEnoughTokenBalanceError { + token_id: Identifier, + identity_id: Identifier, + required_balance: u64, + actual_balance: u64, + action: String, +} + +impl IdentityDoesNotHaveEnoughTokenBalanceError { + pub fn new( + token_id: Identifier, + identity_id: Identifier, + required_balance: u64, + actual_balance: u64, + action: String, + ) -> Self { + Self { + token_id, + identity_id, + required_balance, + actual_balance, + action, + } + } + pub fn token_id(&self) -> &Identifier { + &self.token_id + } + + pub fn identity_id(&self) -> &Identifier { + &self.identity_id + } + + pub fn required_balance(&self) -> u64 { + self.required_balance + } + + pub fn actual_balance(&self) -> u64 { + self.actual_balance + } + + pub fn action(&self) -> &str { + &self.action + } +} + +impl From for ConsensusError { + fn from(err: IdentityDoesNotHaveEnoughTokenBalanceError) -> Self { + Self::StateError(StateError::IdentityDoesNotHaveEnoughTokenBalanceError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_frozen_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_frozen_error.rs new file mode 100644 index 0000000000..6d4a55e609 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_frozen_error.rs @@ -0,0 +1,51 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::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( + "Identity {} account is frozen for token {}. Action attempted: {}", + identity_id, + token_id, + action +)] +#[platform_serialize(unversioned)] +pub struct IdentityTokenAccountFrozenError { + token_id: Identifier, + identity_id: Identifier, + action: String, +} + +impl IdentityTokenAccountFrozenError { + pub fn new(token_id: Identifier, identity_id: Identifier, action: String) -> Self { + Self { + token_id, + identity_id, + action, + } + } + + pub fn token_id(&self) -> &Identifier { + &self.token_id + } + + pub fn identity_id(&self) -> &Identifier { + &self.identity_id + } + + pub fn action(&self) -> &str { + &self.action + } +} + +impl From for ConsensusError { + fn from(err: IdentityTokenAccountFrozenError) -> Self { + Self::StateError(StateError::IdentityTokenAccountFrozenError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_not_frozen_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_not_frozen_error.rs new file mode 100644 index 0000000000..479fcc1a50 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/identity_token_account_not_frozen_error.rs @@ -0,0 +1,51 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::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( + "Identity {} account is not frozen for token {}. Action attempted: {}", + identity_id, + token_id, + action +)] +#[platform_serialize(unversioned)] +pub struct IdentityTokenAccountNotFrozenError { + token_id: Identifier, + identity_id: Identifier, + action: String, +} + +impl IdentityTokenAccountNotFrozenError { + pub fn new(token_id: Identifier, identity_id: Identifier, action: String) -> Self { + Self { + token_id, + identity_id, + action, + } + } + + pub fn token_id(&self) -> &Identifier { + &self.token_id + } + + pub fn identity_id(&self) -> &Identifier { + &self.identity_id + } + + pub fn action(&self) -> &str { + &self.action + } +} + +impl From for ConsensusError { + fn from(err: IdentityTokenAccountNotFrozenError) -> Self { + Self::StateError(StateError::IdentityTokenAccountNotFrozenError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/token/mod.rs b/packages/rs-dpp/src/errors/consensus/state/token/mod.rs new file mode 100644 index 0000000000..6838bc261c --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/mod.rs @@ -0,0 +1,9 @@ +mod identity_does_not_have_enough_token_balance_error; +mod identity_token_account_frozen_error; +mod identity_token_account_not_frozen_error; +mod unauthorized_token_action_error; + +pub use identity_does_not_have_enough_token_balance_error::*; +pub use identity_token_account_frozen_error::*; +pub use identity_token_account_not_frozen_error::*; +pub use unauthorized_token_action_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/token/unauthorized_token_action_error.rs b/packages/rs-dpp/src/errors/consensus/state/token/unauthorized_token_action_error.rs new file mode 100644 index 0000000000..a1275eb7fd --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/token/unauthorized_token_action_error.rs @@ -0,0 +1,64 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; +use crate::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( + "Identity {} is not authorized to perform action: {} on token: {}. Authorized action takers: {:?}", + identity_id, + token_id, + action, + authorized_action_takers +)] +#[platform_serialize(unversioned)] +pub struct UnauthorizedTokenActionError { + token_id: Identifier, + identity_id: Identifier, + action: String, + authorized_action_takers: AuthorizedActionTakers, +} + +impl UnauthorizedTokenActionError { + pub fn new( + token_id: Identifier, + identity_id: Identifier, + action: String, + authorized_action_takers: AuthorizedActionTakers, + ) -> Self { + Self { + token_id, + identity_id, + action, + authorized_action_takers, + } + } + + pub fn token_id(&self) -> &Identifier { + &self.token_id + } + + pub fn identity_id(&self) -> &Identifier { + &self.identity_id + } + + pub fn action(&self) -> &str { + &self.action + } + + pub fn authorized_action_takers(&self) -> &AuthorizedActionTakers { + &self.authorized_action_takers + } +} + +impl From for ConsensusError { + fn from(err: UnauthorizedTokenActionError) -> Self { + Self::StateError(StateError::UnauthorizedTokenActionError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/protocol_error.rs b/packages/rs-dpp/src/errors/protocol_error.rs index b586bfad63..7c5135a005 100644 --- a/packages/rs-dpp/src/errors/protocol_error.rs +++ b/packages/rs-dpp/src/errors/protocol_error.rs @@ -40,6 +40,7 @@ use crate::{ use dashcore::consensus::encode::Error as DashCoreError; +use crate::tokens::errors::TokenError; use crate::version::FeatureVersion; use platform_value::{Error as ValueError, Value}; use platform_version::error::PlatformVersionError; @@ -134,6 +135,9 @@ pub enum ProtocolError { #[error(transparent)] Document(Box), + #[error(transparent)] + Token(Box), + #[error("Generic Error: {0}")] Generic(String), @@ -232,6 +236,12 @@ pub enum ProtocolError { #[error("Public key generation error {0}")] PublicKeyGenerationError(String), + #[error("group member not found in contract: {0}")] + GroupMemberNotFound(String), + + #[error("group not found in contract: {0}")] + GroupNotFound(String), + #[error("corrupted code execution: {0}")] CorruptedCodeExecution(String), @@ -287,6 +297,12 @@ impl From for ProtocolError { } } +impl From for ProtocolError { + fn from(e: TokenError) -> Self { + ProtocolError::Token(Box::new(e)) + } +} + impl From for ProtocolError { fn from(e: SerdeParsingError) -> Self { ProtocolError::ParsingError(e.to_string()) diff --git a/packages/rs-dpp/src/group/action_event.rs b/packages/rs-dpp/src/group/action_event.rs new file mode 100644 index 0000000000..54cb5a950f --- /dev/null +++ b/packages/rs-dpp/src/group/action_event.rs @@ -0,0 +1,12 @@ +use crate::tokens::token_event::TokenEvent; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum GroupActionEvent { + TokenEvent(TokenEvent), +} diff --git a/packages/rs-dpp/src/group/group_action/mod.rs b/packages/rs-dpp/src/group/group_action/mod.rs new file mode 100644 index 0000000000..7e39ab631c --- /dev/null +++ b/packages/rs-dpp/src/group/group_action/mod.rs @@ -0,0 +1,14 @@ +pub mod v0; + +use crate::group::group_action::v0::GroupActionV0; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum GroupAction { + V0(GroupActionV0), +} diff --git a/packages/rs-dpp/src/group/group_action/v0/mod.rs b/packages/rs-dpp/src/group/group_action/v0/mod.rs new file mode 100644 index 0000000000..5f90ce0788 --- /dev/null +++ b/packages/rs-dpp/src/group/group_action/v0/mod.rs @@ -0,0 +1,12 @@ +use crate::group::action_event::GroupActionEvent; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub struct GroupActionV0 { + pub event: GroupActionEvent, +} diff --git a/packages/rs-dpp/src/group/mod.rs b/packages/rs-dpp/src/group/mod.rs new file mode 100644 index 0000000000..1915d41c21 --- /dev/null +++ b/packages/rs-dpp/src/group/mod.rs @@ -0,0 +1,66 @@ +use crate::data_contract::group::{Group, GroupMemberPower}; +use crate::data_contract::GroupContractPosition; +use bincode::{Decode, Encode}; +use derive_more::Display; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +pub mod action_event; +pub mod group_action; +#[derive(Debug, Clone, Copy, Encode, Decode, PartialEq)] +pub enum GroupStateTransitionInfoStatus { + GroupStateTransitionInfoProposer(GroupContractPosition), + GroupStateTransitionInfoOtherSigner(GroupStateTransitionInfo), +} + +impl From for GroupStateTransitionInfo { + fn from(value: GroupStateTransitionInfoStatus) -> Self { + match value { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => GroupStateTransitionInfo { + group_contract_position, + action_id: Default::default(), + action_is_proposer: true, + }, + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => info, + } + } +} + +#[derive(Debug, Clone, Copy, Encode, Decode, Default, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display("ID: {}, Action ID: {}", "id", "action_id")] +pub struct GroupStateTransitionInfo { + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$groupContractPosition") + )] + pub group_contract_position: GroupContractPosition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$groupActionId") + )] + pub action_id: Identifier, + /// This is true if we are the proposer, otherwise we are just voting on a previous action. + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$groupActionIsProposer") + )] + pub action_is_proposer: bool, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct GroupStateTransitionResolvedInfo { + pub group_contract_position: GroupContractPosition, + pub group: Group, + pub action_id: Identifier, + /// This is true if we are the proposer, otherwise we are just voting on a previous action. + pub action_is_proposer: bool, + pub signer_power: GroupMemberPower, +} diff --git a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs index 0a7b020cc1..6829ea6eaf 100644 --- a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs +++ b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/chain/chain_asset_lock_proof.rs @@ -4,7 +4,6 @@ use std::convert::TryFrom; use crate::util::hash::hash_double; use crate::{identifier::Identifier, ProtocolError}; -pub use bincode::{Decode, Encode}; use dashcore::OutPoint; /// Instant Asset Lock Proof is a part of Identity Create and Identity Topup diff --git a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs index 2e97ad7480..a25ded9547 100644 --- a/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs +++ b/packages/rs-dpp/src/identity/state_transition/asset_lock_proof/mod.rs @@ -4,7 +4,7 @@ use dashcore::{OutPoint, Transaction}; use serde::{Deserialize, Deserializer, Serialize}; -pub use bincode::{Decode, Encode}; +use bincode::{Decode, Encode}; pub use instant::*; use platform_value::Value; diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index 27932329aa..af7195d65c 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -41,6 +41,7 @@ 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; @@ -51,10 +52,15 @@ pub mod serialization; pub mod signing; #[cfg(feature = "system_contracts")] pub mod system_data_contracts; + +pub mod tokens; + pub mod voting; #[cfg(feature = "core-types")] pub mod core_types; + +pub mod group; pub mod withdrawal; pub use async_trait; @@ -79,10 +85,21 @@ pub mod prelude { pub type CoreBlockHeight = u32; pub type TimestampMillis = u64; + pub type StartAtIncluded = bool; + pub type TimestampIncluded = bool; pub type Revision = u64; pub type IdentityNonce = u64; + pub type SenderKeyIndex = u32; + pub type RecipientKeyIndex = u32; + + /// The index of the user's key that is used to derive keys that will be used to encrypt the contact's user id in encToUserId and the private data. + pub type RootEncryptionKeyIndex = u32; + + /// The index at which to derive the root encryption key. + pub type DerivationEncryptionKeyIndex = u32; + /// UserFeeIncrease is the additional percentage of the processing fee. /// A 1 here means we pay 1% more in processing fees. A 100 means we pay 100% more. pub type UserFeeIncrease = u16; diff --git a/packages/rs-dpp/src/multi_identity_events/mod.rs b/packages/rs-dpp/src/multi_identity_events/mod.rs new file mode 100644 index 0000000000..6c6558cf9f --- /dev/null +++ b/packages/rs-dpp/src/multi_identity_events/mod.rs @@ -0,0 +1,7 @@ +use platform_value::Identifier; +use std::collections::BTreeSet; + +pub enum ActionTaker { + SingleIdentity(Identifier), + SpecifiedIdentities(BTreeSet), +} diff --git a/packages/rs-dpp/src/nft/mod.rs b/packages/rs-dpp/src/nft/mod.rs index 884906fb1e..bec8e4742a 100644 --- a/packages/rs-dpp/src/nft/mod.rs +++ b/packages/rs-dpp/src/nft/mod.rs @@ -4,7 +4,6 @@ use crate::consensus::ConsensusError; use crate::ProtocolError; use std::fmt; use std::fmt::{Display, Formatter}; - #[derive(Debug, PartialEq, Clone, Copy)] pub enum TradeMode { None = 0, diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index cd97cae4ae..da4c004287 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -1,8 +1,7 @@ use derive_more::From; -use documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use documents_batch_transition::document_transition::DocumentTransition; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; +use state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; pub use abstract_state_transition::state_transition_helpers; @@ -72,19 +71,16 @@ use crate::identity::Purpose; use crate::identity::{IdentityPublicKey, KeyType}; use crate::identity::{KeyID, SecurityLevel}; use crate::prelude::{AssetLockProof, UserFeeIncrease}; -use crate::state_transition::masternode_vote_transition::MasternodeVoteTransitionSignable; -pub use state_transitions::*; - use crate::serialization::Signable; +use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::batch_transition::batched_transition::BatchedTransitionRef; +use crate::state_transition::batch_transition::{BatchTransition, BatchTransitionSignable}; use crate::state_transition::data_contract_create_transition::{ DataContractCreateTransition, DataContractCreateTransitionSignable, }; use crate::state_transition::data_contract_update_transition::{ DataContractUpdateTransition, DataContractUpdateTransitionSignable, }; -use crate::state_transition::documents_batch_transition::{ - DocumentsBatchTransition, DocumentsBatchTransitionSignable, -}; #[cfg(feature = "state-transition-signing")] use crate::state_transition::errors::InvalidSignaturePublicKeyError; #[cfg(feature = "state-transition-signing")] @@ -108,11 +104,14 @@ use crate::state_transition::identity_topup_transition::{ use crate::state_transition::identity_update_transition::{ IdentityUpdateTransition, IdentityUpdateTransitionSignable, }; +use crate::state_transition::masternode_vote_transition::MasternodeVoteTransitionSignable; +use state_transitions::document::batch_transition::batched_transition::token_transition::TokenTransition; +pub use state_transitions::*; use crate::state_transition::masternode_vote_transition::MasternodeVoteTransition; #[cfg(feature = "state-transition-signing")] -use crate::state_transition::state_transitions::document::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use crate::state_transition::state_transitions::document::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; pub type GetDataContractSecurityLevelRequirementFn = fn(Identifier, String) -> Result; @@ -122,7 +121,7 @@ macro_rules! call_method { match $state_transition { StateTransition::DataContractCreate(st) => st.$method($args), StateTransition::DataContractUpdate(st) => st.$method($args), - StateTransition::DocumentsBatch(st) => st.$method($args), + StateTransition::Batch(st) => st.$method($args), StateTransition::IdentityCreate(st) => st.$method($args), StateTransition::IdentityTopUp(st) => st.$method($args), StateTransition::IdentityCreditWithdrawal(st) => st.$method($args), @@ -135,7 +134,7 @@ macro_rules! call_method { match $state_transition { StateTransition::DataContractCreate(st) => st.$method(), StateTransition::DataContractUpdate(st) => st.$method(), - StateTransition::DocumentsBatch(st) => st.$method(), + StateTransition::Batch(st) => st.$method(), StateTransition::IdentityCreate(st) => st.$method(), StateTransition::IdentityTopUp(st) => st.$method(), StateTransition::IdentityCreditWithdrawal(st) => st.$method(), @@ -151,7 +150,7 @@ macro_rules! call_getter_method_identity_signed { match $state_transition { StateTransition::DataContractCreate(st) => Some(st.$method($args)), StateTransition::DataContractUpdate(st) => Some(st.$method($args)), - StateTransition::DocumentsBatch(st) => Some(st.$method($args)), + StateTransition::Batch(st) => Some(st.$method($args)), StateTransition::IdentityCreate(_) => None, StateTransition::IdentityTopUp(_) => None, StateTransition::IdentityCreditWithdrawal(st) => Some(st.$method($args)), @@ -164,7 +163,7 @@ macro_rules! call_getter_method_identity_signed { match $state_transition { StateTransition::DataContractCreate(st) => Some(st.$method()), StateTransition::DataContractUpdate(st) => Some(st.$method()), - StateTransition::DocumentsBatch(st) => Some(st.$method()), + StateTransition::Batch(st) => Some(st.$method()), StateTransition::IdentityCreate(_) => None, StateTransition::IdentityTopUp(_) => None, StateTransition::IdentityCreditWithdrawal(st) => Some(st.$method()), @@ -180,7 +179,7 @@ macro_rules! call_method_identity_signed { match $state_transition { StateTransition::DataContractCreate(st) => st.$method($args), StateTransition::DataContractUpdate(st) => st.$method($args), - StateTransition::DocumentsBatch(st) => st.$method($args), + StateTransition::Batch(st) => st.$method($args), StateTransition::IdentityCreate(_st) => {} StateTransition::IdentityTopUp(_st) => {} StateTransition::IdentityCreditWithdrawal(st) => st.$method($args), @@ -193,7 +192,7 @@ macro_rules! call_method_identity_signed { match $state_transition { StateTransition::DataContractCreate(st) => st.$method(), StateTransition::DataContractUpdate(st) => st.$method(), - StateTransition::DocumentsBatch(st) => st.$method(), + StateTransition::Batch(st) => st.$method(), StateTransition::IdentityCreate(st) => {} StateTransition::IdentityTopUp(st) => {} StateTransition::IdentityCreditWithdrawal(st) => st.$method(), @@ -210,7 +209,7 @@ macro_rules! call_errorable_method_identity_signed { match $state_transition { StateTransition::DataContractCreate(st) => st.$method($args), StateTransition::DataContractUpdate(st) => st.$method($args), - StateTransition::DocumentsBatch(st) => st.$method($args), + StateTransition::Batch(st) => st.$method($args), StateTransition::IdentityCreate(_st) => Err(ProtocolError::CorruptedCodeExecution( "identity create can not be called for identity signing".to_string(), )), @@ -227,7 +226,7 @@ macro_rules! call_errorable_method_identity_signed { match $state_transition { StateTransition::DataContractCreate(st) => st.$method(), StateTransition::DataContractUpdate(st) => st.$method(), - StateTransition::DocumentsBatch(st) => st.$method(), + StateTransition::Batch(st) => st.$method(), StateTransition::IdentityCreate(st) => Err(ProtocolError::CorruptedCodeExecution( "identity create can not be called for identity signing".to_string(), )), @@ -284,7 +283,7 @@ macro_rules! call_errorable_method_identity_signed { pub enum StateTransition { DataContractCreate(DataContractCreateTransition), DataContractUpdate(DataContractUpdateTransition), - DocumentsBatch(DocumentsBatchTransition), + Batch(BatchTransition), IdentityCreate(IdentityCreateTransition), IdentityTopUp(IdentityTopUpTransition), IdentityCreditWithdrawal(IdentityCreditWithdrawalTransition), @@ -349,22 +348,39 @@ impl StateTransition { match self { Self::DataContractCreate(_) => "DataContractCreate".to_string(), Self::DataContractUpdate(_) => "DataContractUpdate".to_string(), - Self::DocumentsBatch(documents_batch_transition) => { + Self::Batch(batch_transition) => { let mut document_transition_types = vec![]; - match documents_batch_transition { - DocumentsBatchTransition::V0(documents_batch_transition_v0) => { - for transition in documents_batch_transition_v0.transitions().iter() { - let document_transition_name = match transition { - DocumentTransition::Create(_) => "Create", - DocumentTransition::Replace(_) => "Replace", - DocumentTransition::Delete(_) => "Delete", - DocumentTransition::Transfer(_) => "Transfer", - DocumentTransition::UpdatePrice(_) => "UpdatePrice", - DocumentTransition::Purchase(_) => "Purchase", - }; - document_transition_types.push(document_transition_name); + for transition in batch_transition.transitions_iter() { + let document_transition_name = match transition { + BatchedTransitionRef::Document(DocumentTransition::Create(_)) => "Create", + BatchedTransitionRef::Document(DocumentTransition::Replace(_)) => "Replace", + BatchedTransitionRef::Document(DocumentTransition::Delete(_)) => "Delete", + BatchedTransitionRef::Document(DocumentTransition::Transfer(_)) => { + "Transfer" + } + BatchedTransitionRef::Document(DocumentTransition::UpdatePrice(_)) => { + "UpdatePrice" + } + BatchedTransitionRef::Document(DocumentTransition::Purchase(_)) => { + "Purchase" + } + BatchedTransitionRef::Token(TokenTransition::Transfer(_)) => { + "TokenTransfer" + } + BatchedTransitionRef::Token(TokenTransition::Mint(_)) => "TokenMint", + BatchedTransitionRef::Token(TokenTransition::Burn(_)) => "TokenBurn", + BatchedTransitionRef::Token(TokenTransition::Freeze(_)) => "TokenFreeze", + BatchedTransitionRef::Token(TokenTransition::Unfreeze(_)) => { + "TokenUnfreeze" + } + BatchedTransitionRef::Token(TokenTransition::DestroyFrozenFunds(_)) => { + "TokenDestroyFrozenFunds" + } + BatchedTransitionRef::Token(TokenTransition::EmergencyAction(_)) => { + "TokenEmergencyAction" } - } + }; + document_transition_types.push(document_transition_name); } format!("DocumentsBatch([{}])", document_transition_types.join(", ")) } @@ -452,7 +468,7 @@ impl StateTransition { st.verify_public_key_level_and_purpose(identity_public_key)?; st.verify_public_key_is_enabled(identity_public_key)?; } - StateTransition::DocumentsBatch(st) => { + StateTransition::Batch(st) => { if identity_public_key.purpose() != Purpose::AUTHENTICATION { return Err(ProtocolError::WrongPublicKeyPurposeError( WrongPublicKeyPurposeError::new( diff --git a/packages/rs-dpp/src/state_transition/serialization.rs b/packages/rs-dpp/src/state_transition/serialization.rs index c36ae53db4..ff55d2653a 100644 --- a/packages/rs-dpp/src/state_transition/serialization.rs +++ b/packages/rs-dpp/src/state_transition/serialization.rs @@ -27,9 +27,9 @@ mod tests { use crate::state_transition::data_contract_update_transition::{ DataContractUpdateTransition, DataContractUpdateTransitionV0, }; - use crate::state_transition::documents_batch_transition::document_transition::action_type::DocumentTransitionActionType; - use crate::state_transition::documents_batch_transition::{ - DocumentsBatchTransition, DocumentsBatchTransitionV0, + use crate::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionType; + use crate::state_transition::batch_transition::{ + BatchTransition, BatchTransitionV1, }; use crate::state_transition::identity_create_transition::v0::IdentityCreateTransitionV0; use crate::state_transition::identity_create_transition::IdentityCreateTransition; @@ -39,7 +39,7 @@ mod tests { use crate::state_transition::public_key_in_creation::accessors::IdentityPublicKeyInCreationV0Setters; use crate::state_transition::StateTransition; use crate::tests::fixtures::{ - get_data_contract_fixture, get_document_transitions_fixture, + get_data_contract_fixture, get_batched_transitions_fixture, get_extended_documents_fixture_with_owner_id_from_contract, raw_instant_asset_lock_proof_fixture, }; @@ -338,11 +338,11 @@ mod tests { ) }) .collect::>(); - let transitions = get_document_transitions_fixture( + let transitions = get_batched_transitions_fixture( [(DocumentTransitionActionType::Create, documents)], &mut nonces, ); - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV1 { owner_id: data_contract.owner_id(), transitions, ..Default::default() diff --git a/packages/rs-dpp/src/state_transition/state_transition_types.rs b/packages/rs-dpp/src/state_transition/state_transition_types.rs index 246f462063..574d18521a 100644 --- a/packages/rs-dpp/src/state_transition/state_transition_types.rs +++ b/packages/rs-dpp/src/state_transition/state_transition_types.rs @@ -21,7 +21,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; pub enum StateTransitionType { #[default] DataContractCreate = 0, - DocumentsBatch = 1, + Batch = 1, IdentityCreate = 2, IdentityTopUp = 3, DataContractUpdate = 4, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/mod.rs new file mode 100644 index 0000000000..fe3a6bef7e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/mod.rs @@ -0,0 +1,99 @@ +mod v0; + +use std::slice::Iter; +use crate::state_transition::batch_transition::batched_transition::{BatchedTransition, BatchedTransitionMutRef, BatchedTransitionRef}; +use crate::state_transition::batch_transition::BatchTransition; +pub use v0::*; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; + +/// Iterator enum for `BatchTransition` that can handle both V0 and V1. +pub enum DocumentBatchIterator<'a> { + V0(Iter<'a, DocumentTransition>), + V1(DocumentBatchV1Iterator<'a>), +} + +/// Iterator for version 1, yielding `BatchedTransitionRef<'a>` items. +pub struct DocumentBatchV1Iterator<'a> { + pub(crate) inner: Iter<'a, BatchedTransition>, +} + +impl<'a> Iterator for DocumentBatchV1Iterator<'a> { + type Item = BatchedTransitionRef<'a>; + + fn next(&mut self) -> Option { + self.inner + .next() + .map(|batched_transition| match batched_transition { + BatchedTransition::Document(doc) => BatchedTransitionRef::Document(doc), + BatchedTransition::Token(tok) => BatchedTransitionRef::Token(tok), + }) + } +} + +impl<'a> Iterator for DocumentBatchIterator<'a> { + type Item = BatchedTransitionRef<'a>; + + fn next(&mut self) -> Option { + match self { + DocumentBatchIterator::V0(iter) => iter.next().map(BatchedTransitionRef::Document), + DocumentBatchIterator::V1(iter) => iter.next(), + } + } +} + +impl DocumentsBatchTransitionAccessorsV0 for BatchTransition { + type IterType<'a> + = DocumentBatchIterator<'a> + where + Self: 'a; + + /// Iterator for `BatchedTransitionRef` items. + fn transitions_iter<'a>(&'a self) -> Self::IterType<'a> { + match self { + BatchTransition::V0(v0) => DocumentBatchIterator::V0(v0.transitions.iter()), + BatchTransition::V1(v1) => DocumentBatchIterator::V1(DocumentBatchV1Iterator { + inner: v1.transitions.iter(), + }), + } + } + + fn transitions_len(&self) -> usize { + match self { + BatchTransition::V0(v0) => v0.transitions.len(), + BatchTransition::V1(v1) => v1.transitions.len(), + } + } + + fn transitions_are_empty(&self) -> bool { + match self { + BatchTransition::V0(v0) => v0.transitions.is_empty(), + BatchTransition::V1(v1) => v1.transitions.is_empty(), + } + } + + fn first_transition(&self) -> Option { + match self { + BatchTransition::V0(v0) => v0 + .transitions + .first() + .map(|document_transition| BatchedTransitionRef::Document(document_transition)), + BatchTransition::V1(v1) => v1 + .transitions + .first() + .map(|batch_transition| batch_transition.borrow_as_ref()), + } + } + + fn first_transition_mut(&mut self) -> Option { + match self { + BatchTransition::V0(v0) => v0 + .transitions + .first_mut() + .map(|document_transition| BatchedTransitionMutRef::Document(document_transition)), + BatchTransition::V1(v1) => v1 + .transitions + .first_mut() + .map(|batch_transition| batch_transition.borrow_as_mut()), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/v0/mod.rs new file mode 100644 index 0000000000..767cff2993 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/accessors/v0/mod.rs @@ -0,0 +1,19 @@ +use crate::state_transition::batch_transition::batched_transition::{ + BatchedTransitionMutRef, BatchedTransitionRef, +}; +pub trait DocumentsBatchTransitionAccessorsV0 { + /// Associated type for the iterator. + type IterType<'a>: Iterator> + where + Self: 'a; + + /// Returns an iterator over the `BatchedTransitionRef` items. + fn transitions_iter<'a>(&'a self) -> Self::IterType<'a>; + + fn transitions_len(&self) -> usize; + fn transitions_are_empty(&self) -> bool; + + fn first_transition(&self) -> Option; + + fn first_transition_mut(&mut self) -> Option; +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/document_base_transition_trait.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/document_base_transition_trait.rs new file mode 100644 index 0000000000..d934498534 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/document_base_transition_trait.rs @@ -0,0 +1,16 @@ +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; + +pub trait DocumentBaseTransitionAccessors { + /// Returns a reference to the `base` field of the `DocumentCreateTransitionV0`. + fn base(&self) -> &DocumentBaseTransition; + + /// Returns a mut reference to the `base` field of the `DocumentCreateTransitionV0`. + fn base_mut(&mut self) -> &mut DocumentBaseTransition; + + /// Sets the value of the `base` field in the `DocumentCreateTransitionV0`. + /// + /// # Arguments + /// + /// * `base` - A value of type `DocumentBaseTransition` to set. + fn set_base(&mut self, base: DocumentBaseTransition); +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/fields.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs similarity index 75% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/fields.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs index b7e0135ed0..df730f10f9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/fields.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/fields.rs @@ -1,4 +1,4 @@ -pub(in crate::state_transition::state_transitions::document::documents_batch_transition) mod property_names { +pub(in crate::state_transition::state_transitions::document::batch_transition) mod property_names { pub const ID: &str = "$id"; pub const DATA_CONTRACT_ID: &str = "$dataContractId"; pub const DOCUMENT_TYPE: &str = "$type"; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs similarity index 84% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs index e500bbd5bd..88c136d585 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/from_document.rs @@ -1,8 +1,8 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::Document; use crate::prelude::IdentityNonce; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs similarity index 96% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs index 6d80cc2d87..d430a12ba7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod document_base_transition_trait; mod fields; mod from_document; pub mod v0; @@ -8,7 +9,7 @@ mod v0_methods; feature = "state-transition-json-conversion" ))] use crate::data_contract::DataContract; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::{ +use crate::state_transition::batch_transition::document_base_transition::v0::{ DocumentBaseTransitionV0, DocumentTransitionObjectLike, }; #[cfg(any( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/from_document.rs similarity index 77% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/from_document.rs index 7d3e6ef348..b067edad06 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/from_document.rs @@ -2,10 +2,10 @@ use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; impl DocumentBaseTransitionV0 { - pub(in crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_base_transition) fn from_document( + pub(in crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_base_transition) fn from_document( document: &Document, document_type: DocumentTypeRef, identity_contract_nonce: IdentityNonce, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs similarity index 98% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs index f5b245bece..9477075d48 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/mod.rs @@ -21,7 +21,7 @@ use crate::data_contract::accessors::v0::DataContractV0Getters; use crate::identifier::Identifier; use crate::prelude::IdentityNonce; #[cfg(feature = "state-transition-value-conversion")] -use crate::state_transition::documents_batch_transition::document_base_transition::property_names; +use crate::state_transition::batch_transition::document_base_transition::property_names; #[cfg(any( feature = "state-transition-json-conversion", feature = "state-transition-value-conversion" diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs similarity index 94% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs index c332648a54..f3c6beb7ee 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0/v0_methods.rs @@ -1,4 +1,4 @@ -use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; use crate::prelude::IdentityNonce; use platform_value::Identifier; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs similarity index 87% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs index c7a543b555..053865b056 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_base_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_base_transition/v0_methods.rs @@ -1,6 +1,6 @@ -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::prelude::IdentityNonce; use platform_value::Identifier; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/convertible.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs similarity index 90% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/convertible.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs index bca79958ba..b1d5a81ed0 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/convertible.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/convertible.rs @@ -7,24 +7,24 @@ use crate::data_contract::document_type::accessors::DocumentTypeV0Getters; feature = "state-transition-value-conversion" ))] use crate::prelude::DataContract; -#[cfg(feature = "state-transition-json-conversion")] -use crate::state_transition::data_contract_update_transition::IDENTIFIER_FIELDS; #[cfg(any( feature = "state-transition-json-conversion", feature = "state-transition-value-conversion" ))] -use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentTransitionObjectLike; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentTransitionObjectLike; #[cfg(feature = "state-transition-json-conversion")] -use crate::state_transition::documents_batch_transition::document_create_transition::v0::BINARY_FIELDS; +use crate::state_transition::batch_transition::document_create_transition::v0::BINARY_FIELDS; #[cfg(any( feature = "state-transition-json-conversion", feature = "state-transition-value-conversion" ))] -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; #[cfg(feature = "state-transition-value-conversion")] -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; #[cfg(feature = "state-transition-value-conversion")] -use crate::state_transition::documents_batch_transition::fields::property_names::STATE_TRANSITION_PROTOCOL_VERSION; +use crate::state_transition::batch_transition::fields::property_names::STATE_TRANSITION_PROTOCOL_VERSION; +#[cfg(feature = "state-transition-json-conversion")] +use crate::state_transition::data_contract_update_transition::IDENTIFIER_FIELDS; #[cfg(any( feature = "state-transition-json-conversion", feature = "state-transition-value-conversion" diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs similarity index 86% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs index e275f72647..7ade005e6c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/from_document.rs @@ -1,8 +1,8 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::Document; use crate::prelude::IdentityNonce; -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; -use crate::state_transition::documents_batch_transition::document_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::batched_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/mod.rs similarity index 97% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/mod.rs index cde6d5ae29..dfc4682872 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/mod.rs @@ -6,7 +6,7 @@ mod v0_methods; use crate::block::block_info::BlockInfo; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::Document; -use crate::state_transition::documents_batch_transition::document_create_transition::v0::DocumentFromCreateTransitionV0; +use crate::state_transition::batch_transition::document_create_transition::v0::DocumentFromCreateTransitionV0; use crate::ProtocolError; use bincode::{Decode, Encode}; use derive_more::{Display, From}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs similarity index 84% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs index 3132a4ba07..633c72ffcc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/from_document.rs @@ -2,8 +2,8 @@ use crate::data_contract::document_type::methods::DocumentTypeV0Methods; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs similarity index 97% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs index 27c968b20b..7296c50382 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/mod.rs @@ -24,17 +24,17 @@ use crate::data_contract::document_type::methods::DocumentTypeV0Methods; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::{Document, DocumentV0}; use crate::fee::Credits; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; #[cfg(feature = "state-transition-value-conversion")] -use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentTransitionObjectLike; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentTransitionObjectLike; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use derive_more::Display; #[cfg(feature = "state-transition-value-conversion")] use platform_value::btreemap_extensions::BTreeValueRemoveTupleFromMapHelper; use platform_version::version::PlatformVersion; #[cfg(feature = "state-transition-value-conversion")] -use crate::state_transition::documents_batch_transition; +use crate::state_transition::batch_transition; mod property_names { pub const ENTROPY: &str = "$entropy"; @@ -86,7 +86,9 @@ impl DocumentCreateTransitionV0 { data_contract: DataContract, ) -> Result { let identity_contract_nonce = map - .remove_integer(documents_batch_transition::document_base_transition::property_names::IDENTITY_CONTRACT_NONCE) + .remove_integer( + batch_transition::document_base_transition::property_names::IDENTITY_CONTRACT_NONCE, + ) .map_err(ProtocolError::ValueError)?; Ok(Self { base: DocumentBaseTransition::V0(DocumentBaseTransitionV0::from_value_map_consume( @@ -386,8 +388,8 @@ impl DocumentFromCreateTransitionV0 for Document { #[cfg(test)] mod test { - use crate::data_contract::data_contract::DataContractV0; - use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; + use crate::data_contract::v0::DataContractV0; + use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; use platform_value::btreemap_extensions::BTreeValueMapHelper; use platform_value::{platform_value, BinaryData, Bytes32, Identifier}; use platform_version::version::LATEST_PLATFORM_VERSION; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs similarity index 76% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs index e5e2aa8710..e19bcb8ec8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0/v0_methods.rs @@ -1,25 +1,13 @@ -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; use platform_value::Value; use crate::fee::Credits; use std::collections::BTreeMap; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; -pub trait DocumentCreateTransitionV0Methods { - /// Returns a reference to the `base` field of the `DocumentCreateTransitionV0`. - fn base(&self) -> &DocumentBaseTransition; - - /// Returns a mut reference to the `base` field of the `DocumentCreateTransitionV0`. - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - - /// Sets the value of the `base` field in the `DocumentCreateTransitionV0`. - /// - /// # Arguments - /// - /// * `base` - A value of type `DocumentBaseTransition` to set. - fn set_base(&mut self, base: DocumentBaseTransition); - +pub trait DocumentCreateTransitionV0Methods: DocumentBaseTransitionAccessors { /// Returns a reference to the `entropy` field of the `DocumentCreateTransitionV0`. fn entropy(&self) -> [u8; 32]; @@ -48,7 +36,7 @@ pub trait DocumentCreateTransitionV0Methods { fn clear_prefunded_voting_balance(&mut self); } -impl DocumentCreateTransitionV0Methods for DocumentCreateTransitionV0 { +impl DocumentBaseTransitionAccessors for DocumentCreateTransitionV0 { fn base(&self) -> &DocumentBaseTransition { &self.base } @@ -60,7 +48,9 @@ impl DocumentCreateTransitionV0Methods for DocumentCreateTransitionV0 { fn set_base(&mut self, base: DocumentBaseTransition) { self.base = base; } +} +impl DocumentCreateTransitionV0Methods for DocumentCreateTransitionV0 { fn entropy(&self) -> [u8; 32] { self.entropy } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs similarity index 80% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs index 11d349f56c..da248d5393 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_create_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_create_transition/v0_methods.rs @@ -1,11 +1,12 @@ use std::collections::BTreeMap; use platform_value::{Value}; use crate::fee::Credits; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; -use crate::state_transition::documents_batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -impl DocumentCreateTransitionV0Methods for DocumentCreateTransition { +impl DocumentBaseTransitionAccessors for DocumentCreateTransition { fn base(&self) -> &DocumentBaseTransition { match self { DocumentCreateTransition::V0(v0) => &v0.base, @@ -23,7 +24,9 @@ impl DocumentCreateTransitionV0Methods for DocumentCreateTransition { DocumentCreateTransition::V0(v0) => v0.base = base, } } +} +impl DocumentCreateTransitionV0Methods for DocumentCreateTransition { fn entropy(&self) -> [u8; 32] { match self { DocumentCreateTransition::V0(v0) => v0.entropy, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs similarity index 85% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs index 3c6dfa6b80..a3eafe8c32 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/from_document.rs @@ -4,8 +4,8 @@ use crate::prelude::IdentityNonce; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::state_transition::documents_batch_transition::document_transition::{DocumentDeleteTransition}; -use crate::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; +use crate::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; +use crate::state_transition::batch_transition::batched_transition::DocumentDeleteTransition; impl DocumentDeleteTransition { pub fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/mod.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/mod.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs similarity index 69% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs index 4fac1aff9f..9a93935028 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/from_document.rs @@ -1,10 +1,10 @@ -use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::data_contract::document_type::{DocumentTypeRef}; -use crate::document::{Document}; +use crate::data_contract::document_type::DocumentTypeRef; +use crate::document::Document; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; +use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentDeleteTransitionV0 { pub(crate) fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/mod.rs similarity index 85% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/mod.rs index 34d4ac9855..633c7d8381 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/mod.rs @@ -1,7 +1,7 @@ mod from_document; pub mod v0_methods; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use bincode::{Decode, Encode}; use derive_more::Display; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..861334a602 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0/v0_methods.rs @@ -0,0 +1,17 @@ +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; + +impl DocumentBaseTransitionAccessors for DocumentDeleteTransitionV0 { + fn base(&self) -> &DocumentBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut DocumentBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: DocumentBaseTransition) { + self.base = base + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0_methods.rs similarity index 51% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0_methods.rs index 099c95e8f3..8fd1b1f31c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_delete_transition/v0_methods.rs @@ -1,8 +1,8 @@ -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_delete_transition::v0::v0_methods::DocumentDeleteTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::DocumentDeleteTransition; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::DocumentDeleteTransition; -impl DocumentDeleteTransitionV0Methods for DocumentDeleteTransition { +impl DocumentBaseTransitionAccessors for DocumentDeleteTransition { fn base(&self) -> &DocumentBaseTransition { match self { DocumentDeleteTransition::V0(v0) => &v0.base, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs similarity index 85% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs index d4b913405f..b7f24dc3d1 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/from_document.rs @@ -5,8 +5,8 @@ use crate::prelude::IdentityNonce; use crate::ProtocolError; use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::state_transition::documents_batch_transition::document_transition::{DocumentPurchaseTransition}; -use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +use crate::state_transition::batch_transition::batched_transition::DocumentPurchaseTransition; impl DocumentPurchaseTransition { pub fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/mod.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/mod.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs similarity index 79% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs index 80bfc2115c..9c2eb59f76 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/from_document.rs @@ -1,12 +1,12 @@ -use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::data_contract::document_type::{DocumentTypeRef}; -use crate::document::{Document, DocumentV0Getters}; +use crate::data_contract::document_type::DocumentTypeRef; use crate::document::errors::DocumentError; +use crate::document::{Document, DocumentV0Getters}; use crate::fee::Credits; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentPurchaseTransitionV0 { pub(crate) fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/mod.rs similarity index 90% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/mod.rs index 5a4ca1e8ba..3b798177be 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/mod.rs @@ -1,7 +1,7 @@ mod from_document; pub mod v0_methods; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use bincode::{Decode, Encode}; use derive_more::Display; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/v0_methods.rs similarity index 53% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/v0_methods.rs index 95333296e4..41f6b423af 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0/v0_methods.rs @@ -1,20 +1,10 @@ use crate::fee::Credits; use crate::prelude::Revision; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; - -pub trait DocumentPurchaseTransitionV0Methods { - /// Returns a reference to the `base` field of the `DocumentCreateTransitionV0`. - fn base(&self) -> &DocumentBaseTransition; - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - - /// Sets the value of the `base` field in the `DocumentCreateTransitionV0`. - /// - /// # Arguments - /// - /// * `base` - A value of type `DocumentBaseTransition` to set. - fn set_base(&mut self, base: DocumentBaseTransition); +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +pub trait DocumentPurchaseTransitionV0Methods: DocumentBaseTransitionAccessors { /// Returns a reference to the `revision` field of the `DocumentReplaceTransitionV0`. fn revision(&self) -> Revision; @@ -23,7 +13,7 @@ pub trait DocumentPurchaseTransitionV0Methods { fn price(&self) -> Credits; } -impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransitionV0 { +impl DocumentBaseTransitionAccessors for DocumentPurchaseTransitionV0 { fn base(&self) -> &DocumentBaseTransition { &self.base } @@ -33,9 +23,11 @@ impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransitionV0 { } fn set_base(&mut self, base: DocumentBaseTransition) { - self.base = base + self.base = base; } +} +impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransitionV0 { fn revision(&self) -> Revision { self.revision } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0_methods.rs similarity index 65% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0_methods.rs index 86c2fe8f19..8918323373 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_purchase_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_purchase_transition/v0_methods.rs @@ -1,10 +1,11 @@ use crate::fee::Credits; use crate::prelude::Revision; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::DocumentPurchaseTransition; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::DocumentPurchaseTransition; -impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransition { +impl DocumentBaseTransitionAccessors for DocumentPurchaseTransition { fn base(&self) -> &DocumentBaseTransition { match self { DocumentPurchaseTransition::V0(v0) => &v0.base, @@ -22,7 +23,9 @@ impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransition { DocumentPurchaseTransition::V0(v0) => v0.base = base, } } +} +impl DocumentPurchaseTransitionV0Methods for DocumentPurchaseTransition { fn revision(&self) -> Revision { match self { DocumentPurchaseTransition::V0(v0) => v0.revision, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs similarity index 79% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs index 059da81c22..1d2923a1f3 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/from_document.rs @@ -1,10 +1,10 @@ -use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::data_contract::document_type::{DocumentTypeRef}; -use crate::document::{Document}; +use crate::data_contract::document_type::DocumentTypeRef; +use crate::document::Document; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; +use crate::state_transition::batch_transition::batched_transition::DocumentReplaceTransition; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_transition::{DocumentReplaceTransition}; -use crate::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; +use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentReplaceTransition { pub fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/mod.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/mod.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs similarity index 79% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs index 5fbd783eb6..4b5903c87a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/from_document.rs @@ -1,11 +1,11 @@ -use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::data_contract::document_type::{DocumentTypeRef}; -use crate::document::{Document, DocumentV0Getters}; +use crate::data_contract::document_type::DocumentTypeRef; use crate::document::errors::DocumentError; +use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; +use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentReplaceTransitionV0 { pub(crate) fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/mod.rs similarity index 98% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/mod.rs index 13833cabaf..1aae0624bf 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/mod.rs @@ -18,8 +18,8 @@ use platform_version::version::PlatformVersion; use std::collections::BTreeMap; pub use super::super::document_base_transition::IDENTIFIER_FIELDS; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; mod property_names { pub const REVISION: &str = "$revision"; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/v0_methods.rs similarity index 68% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/v0_methods.rs index 9bee325bb1..61dec36af2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0/v0_methods.rs @@ -3,20 +3,11 @@ use platform_value::Value; use std::collections::BTreeMap; use crate::prelude::Revision; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; - -use crate::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; - -pub trait DocumentReplaceTransitionV0Methods { - /// Returns a reference to the `base` field of the `DocumentReplaceTransitionV0`. - fn base(&self) -> &DocumentBaseTransition; - /// Returns a mut reference to the `base` field of the `DocumentReplaceTransitionV0`. - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - - /// Sets the value of the `base` field in the `DocumentReplaceTransitionV0`. - fn set_base(&mut self, base: DocumentBaseTransition); - +pub trait DocumentReplaceTransitionV0Methods: DocumentBaseTransitionAccessors { /// Returns a reference to the `revision` field of the `DocumentReplaceTransitionV0`. fn revision(&self) -> Revision; @@ -33,7 +24,7 @@ pub trait DocumentReplaceTransitionV0Methods { fn set_data(&mut self, data: BTreeMap); } -impl DocumentReplaceTransitionV0Methods for DocumentReplaceTransitionV0 { +impl DocumentBaseTransitionAccessors for DocumentReplaceTransitionV0 { fn base(&self) -> &DocumentBaseTransition { &self.base } @@ -45,7 +36,9 @@ impl DocumentReplaceTransitionV0Methods for DocumentReplaceTransitionV0 { fn set_base(&mut self, base: DocumentBaseTransition) { self.base = base; } +} +impl DocumentReplaceTransitionV0Methods for DocumentReplaceTransitionV0 { fn revision(&self) -> Revision { self.revision } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0_methods.rs similarity index 71% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0_methods.rs index 29f79a05e2..ad52fdadd0 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_replace_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_replace_transition/v0_methods.rs @@ -1,11 +1,12 @@ use std::collections::BTreeMap; use platform_value::Value; use crate::prelude::Revision; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::DocumentReplaceTransition; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::DocumentReplaceTransition; -impl DocumentReplaceTransitionV0Methods for DocumentReplaceTransition { +impl DocumentBaseTransitionAccessors for DocumentReplaceTransition { fn base(&self) -> &DocumentBaseTransition { match self { DocumentReplaceTransition::V0(v0) => &v0.base, @@ -23,7 +24,9 @@ impl DocumentReplaceTransitionV0Methods for DocumentReplaceTransition { DocumentReplaceTransition::V0(v0) => v0.base = base, } } +} +impl DocumentReplaceTransitionV0Methods for DocumentReplaceTransition { fn revision(&self) -> Revision { match self { DocumentReplaceTransition::V0(v0) => v0.revision, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs similarity index 84% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs index abfbf806df..17d0166f09 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/from_document.rs @@ -1,10 +1,12 @@ -use platform_value::Identifier; -use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::data_contract::document_type::{DocumentTypeRef}; -use crate::document::{Document}; +use crate::data_contract::document_type::DocumentTypeRef; +use crate::document::Document; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::{ + DocumentTransferTransition, DocumentTransferTransitionV0, +}; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_transition::document_transfer_transition::{DocumentTransferTransition, DocumentTransferTransitionV0}; +use platform_value::Identifier; +use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentTransferTransition { pub fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/mod.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/mod.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs similarity index 79% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs index 77a4d59c6d..7f182eb46a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/from_document.rs @@ -1,12 +1,12 @@ -use platform_value::Identifier; -use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::data_contract::document_type::{DocumentTypeRef}; -use crate::document::{Document, DocumentV0Getters}; +use crate::data_contract::document_type::DocumentTypeRef; use crate::document::errors::DocumentError; +use crate::document::{Document, DocumentV0Getters}; use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_transfer_transition::DocumentTransferTransitionV0; +use platform_value::Identifier; +use platform_version::version::{FeatureVersion, PlatformVersion}; impl DocumentTransferTransitionV0 { pub(crate) fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/mod.rs similarity index 92% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/mod.rs index 3708794cf7..d8a7e7e41f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/mod.rs @@ -10,7 +10,7 @@ use platform_value::Identifier; use serde::{Deserialize, Serialize}; pub use super::super::document_base_transition::IDENTIFIER_FIELDS; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; mod property_names { pub const REVISION: &str = "$revision"; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/v0_methods.rs similarity index 69% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/v0_methods.rs index 6e4b833115..2dd4b95d4e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0/v0_methods.rs @@ -1,20 +1,11 @@ use platform_value::Identifier; use crate::prelude::Revision; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; - -use crate::state_transition::documents_batch_transition::document_transition::document_transfer_transition::DocumentTransferTransitionV0; - -pub trait DocumentTransferTransitionV0Methods { - /// Returns a reference to the `base` field of the `DocumentReplaceTransitionV0`. - fn base(&self) -> &DocumentBaseTransition; - /// Returns a mut reference to the `base` field of the `DocumentReplaceTransitionV0`. - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - - /// Sets the value of the `base` field in the `DocumentReplaceTransitionV0`. - fn set_base(&mut self, base: DocumentBaseTransition); - +pub trait DocumentTransferTransitionV0Methods: DocumentBaseTransitionAccessors { /// Returns a reference to the `revision` field of the `DocumentReplaceTransitionV0`. fn revision(&self) -> Revision; @@ -31,7 +22,7 @@ pub trait DocumentTransferTransitionV0Methods { fn set_recipient_owner_id(&mut self, recipient_owner_id: Identifier); } -impl DocumentTransferTransitionV0Methods for DocumentTransferTransitionV0 { +impl DocumentBaseTransitionAccessors for DocumentTransferTransitionV0 { fn base(&self) -> &DocumentBaseTransition { &self.base } @@ -43,7 +34,9 @@ impl DocumentTransferTransitionV0Methods for DocumentTransferTransitionV0 { fn set_base(&mut self, base: DocumentBaseTransition) { self.base = base; } +} +impl DocumentTransferTransitionV0Methods for DocumentTransferTransitionV0 { fn revision(&self) -> Revision { self.revision } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0_methods.rs similarity index 72% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0_methods.rs index adeff540c0..e4dc722b78 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_transfer_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transfer_transition/v0_methods.rs @@ -1,10 +1,11 @@ use platform_value::Identifier; use crate::prelude::Revision; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransferTransition; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::DocumentTransferTransition; -impl DocumentTransferTransitionV0Methods for DocumentTransferTransition { +impl DocumentBaseTransitionAccessors for DocumentTransferTransition { fn base(&self) -> &DocumentBaseTransition { match self { DocumentTransferTransition::V0(v0) => &v0.base, @@ -22,7 +23,9 @@ impl DocumentTransferTransitionV0Methods for DocumentTransferTransition { DocumentTransferTransition::V0(v0) => v0.base = base, } } +} +impl DocumentTransferTransitionV0Methods for DocumentTransferTransition { fn revision(&self) -> Revision { match self { DocumentTransferTransition::V0(v0) => v0.revision, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs similarity index 74% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs index 448dffcfea..535f79932e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition.rs @@ -1,74 +1,21 @@ +use platform_value::{Identifier, Value}; use std::collections::BTreeMap; - -use bincode::{Decode, Encode}; -use derive_more::From; +use derive_more::{Display, From}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; - -use crate::prelude::{Identifier, IdentityNonce}; -use document_base_transition::DocumentBaseTransition; - -pub mod action_type; -pub mod document_base_transition; -pub mod document_create_transition; -pub mod document_delete_transition; -pub mod document_purchase_transition; -pub mod document_replace_transition; -pub mod document_transfer_transition; -pub mod document_update_price_transition; - -use crate::prelude::Revision; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use derive_more::Display; -pub use document_create_transition::DocumentCreateTransition; -pub use document_delete_transition::DocumentDeleteTransition; -pub use document_replace_transition::DocumentReplaceTransition; -pub use document_transfer_transition::DocumentTransferTransition; -pub use document_purchase_transition::DocumentPurchaseTransition; -pub use document_update_price_transition::DocumentUpdatePriceTransition; -use platform_value::Value; -use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; - -use crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -use crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; -use crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_delete_transition::v0::v0_methods::DocumentDeleteTransitionV0Methods; -use crate::state_transition::state_transitions::document::documents_batch_transition::document_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; - -pub const PROPERTY_ACTION: &str = "$action"; - -pub trait DocumentTransitionV0Methods { - fn base(&self) -> &DocumentBaseTransition; - /// returns the value of dynamic property. The dynamic property is a property that is not specified in protocol - /// the `path` supports dot-syntax: i.e: property.internal_property - fn get_dynamic_property(&self, path: &str) -> Option<&Value>; - /// get the id - fn get_id(&self) -> Identifier; - /// get the document type - fn document_type_name(&self) -> &String; - /// get the data contract id - fn data_contract_id(&self) -> Identifier; - /// get the data of the transition if exits - fn data(&self) -> Option<&BTreeMap>; - /// get the revision of transition if exits - fn revision(&self) -> Option; - - /// get the identity contract nonce - fn identity_contract_nonce(&self) -> IdentityNonce; - #[cfg(test)] - /// Inserts the dynamic property into the document - fn insert_dynamic_property(&mut self, property_name: String, value: Value); - /// set data contract's ID - fn set_data_contract_id(&mut self, id: Identifier); - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - fn data_mut(&mut self) -> Option<&mut BTreeMap>; - - // sets revision of the transition - fn set_revision(&mut self, revision: Revision); - - // sets identity contract nonce - fn set_identity_contract_nonce(&mut self, nonce: IdentityNonce); -} +use bincode::{Encode, Decode}; +use crate::prelude::{IdentityNonce, Revision}; +use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenTransferTransition, TokenUnfreezeTransition}; +use crate::state_transition::batch_transition::batched_transition::{DocumentPurchaseTransition, DocumentTransferTransition, DocumentUpdatePriceTransition}; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use crate::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use crate::state_transition::batch_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; +use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; #[derive(Debug, Clone, Encode, Decode, From, PartialEq, Display)] #[cfg_attr( @@ -95,15 +42,15 @@ pub enum DocumentTransition { Purchase(DocumentPurchaseTransition), } -impl DocumentTransition { - pub fn as_transition_create(&self) -> Option<&DocumentCreateTransition> { +impl BatchTransitionResolversV0 for DocumentTransition { + fn as_transition_create(&self) -> Option<&DocumentCreateTransition> { if let Self::Create(ref t) = self { Some(t) } else { None } } - pub fn as_transition_replace(&self) -> Option<&DocumentReplaceTransition> { + fn as_transition_replace(&self) -> Option<&DocumentReplaceTransition> { if let Self::Replace(ref t) = self { Some(t) } else { @@ -111,7 +58,7 @@ impl DocumentTransition { } } - pub fn as_transition_delete(&self) -> Option<&DocumentDeleteTransition> { + fn as_transition_delete(&self) -> Option<&DocumentDeleteTransition> { if let Self::Delete(ref t) = self { Some(t) } else { @@ -119,7 +66,7 @@ impl DocumentTransition { } } - pub fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition> { + fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition> { if let Self::Transfer(ref t) = self { Some(t) } else { @@ -127,13 +74,76 @@ impl DocumentTransition { } } - pub fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition> { + fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition> { if let Self::Purchase(ref t) = self { Some(t) } else { None } } + + fn as_transition_token_burn(&self) -> Option<&TokenBurnTransition> { + None + } + + fn as_transition_token_mint(&self) -> Option<&TokenMintTransition> { + None + } + + fn as_transition_token_transfer(&self) -> Option<&TokenTransferTransition> { + None + } + + fn as_transition_token_freeze(&self) -> Option<&TokenFreezeTransition> { + None + } + + fn as_transition_token_unfreeze(&self) -> Option<&TokenUnfreezeTransition> { + None + } + + fn as_transition_token_destroy_frozen_funds( + &self, + ) -> Option<&TokenDestroyFrozenFundsTransition> { + None + } + + fn as_transition_token_emergency_action(&self) -> Option<&TokenEmergencyActionTransition> { + None + } +} + +pub trait DocumentTransitionV0Methods { + fn base(&self) -> &DocumentBaseTransition; + /// returns the value of dynamic property. The dynamic property is a property that is not specified in protocol + /// the `path` supports dot-syntax: i.e: property.internal_property + fn get_dynamic_property(&self, path: &str) -> Option<&Value>; + /// get the id + fn get_id(&self) -> Identifier; + /// get the document type + fn document_type_name(&self) -> &String; + /// get the data contract id + fn data_contract_id(&self) -> Identifier; + /// get the data of the transition if exits + fn data(&self) -> Option<&BTreeMap>; + /// get the revision of transition if exits + fn revision(&self) -> Option; + + /// get the identity contract nonce + fn identity_contract_nonce(&self) -> IdentityNonce; + #[cfg(test)] + /// Inserts the dynamic property into the document + fn insert_dynamic_property(&mut self, property_name: String, value: Value); + /// set data contract's ID + fn set_data_contract_id(&mut self, id: Identifier); + fn base_mut(&mut self) -> &mut DocumentBaseTransition; + fn data_mut(&mut self) -> Option<&mut BTreeMap>; + + // sets revision of the transition + fn set_revision(&mut self, revision: Revision); + + // sets identity contract nonce + fn set_identity_contract_nonce(&mut self, nonce: IdentityNonce); } impl DocumentTransitionV0Methods for DocumentTransition { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition_action_type.rs similarity index 78% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition_action_type.rs index fd7c376f7b..2fadc90838 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/action_type.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_transition_action_type.rs @@ -1,4 +1,4 @@ -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; use crate::ProtocolError; // @append-only @@ -13,11 +13,11 @@ pub enum DocumentTransitionActionType { IgnoreWhileBumpingRevision, } -pub trait TransitionActionTypeGetter { +pub trait DocumentTransitionActionTypeGetter { fn action_type(&self) -> DocumentTransitionActionType; } -impl TransitionActionTypeGetter for DocumentTransition { +impl DocumentTransitionActionTypeGetter for DocumentTransition { fn action_type(&self) -> DocumentTransitionActionType { match self { DocumentTransition::Create(_) => DocumentTransitionActionType::Create, @@ -39,6 +39,8 @@ impl TryFrom<&str> for DocumentTransitionActionType { "replace" => Ok(DocumentTransitionActionType::Replace), "delete" => Ok(DocumentTransitionActionType::Delete), "transfer" => Ok(DocumentTransitionActionType::Transfer), + "updatePrice" | "update_price" => Ok(DocumentTransitionActionType::UpdatePrice), + "purchase" => Ok(DocumentTransitionActionType::Purchase), action_type => Err(ProtocolError::Generic(format!( "unknown action type {action_type}" ))), diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs similarity index 85% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs index 4f26ff90bd..39e2877d60 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/from_document.rs @@ -4,8 +4,8 @@ use crate::document::{Document}; use crate::fee::Credits; use crate::prelude::IdentityNonce; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_transition::DocumentUpdatePriceTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; +use crate::state_transition::batch_transition::batched_transition::DocumentUpdatePriceTransition; +use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; impl DocumentUpdatePriceTransition { pub fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/mod.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/mod.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/from_document.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs similarity index 82% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/from_document.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs index 570a3fb561..2a6c778587 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/from_document.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/from_document.rs @@ -5,8 +5,8 @@ use crate::document::errors::DocumentError; use crate::fee::Credits; use crate::prelude::IdentityNonce; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; impl DocumentUpdatePriceTransitionV0 { pub(crate) fn from_document( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/mod.rs similarity index 99% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/mod.rs index 8e264bba97..fbca7eb677 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/mod.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::fee::Credits; pub use super::super::document_base_transition::IDENTIFIER_FIELDS; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; mod property_names { pub const REVISION: &str = "$revision"; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/v0_methods.rs similarity index 62% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/v0_methods.rs index 74b27a3589..aa96cdc5cc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0/v0_methods.rs @@ -1,19 +1,10 @@ use crate::fee::Credits; use crate::prelude::Revision; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; - -use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; - -pub trait DocumentUpdatePriceTransitionV0Methods { - /// Returns a reference to the `base` field of the `DocumentUpdatePriceTransitionV0`. - fn base(&self) -> &DocumentBaseTransition; - /// Returns a mut reference to the `base` field of the `DocumentUpdatePriceTransitionV0`. - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - - /// Sets the value of the `base` field in the `DocumentUpdatePriceTransitionV0`. - fn set_base(&mut self, base: DocumentBaseTransition); - +pub trait DocumentUpdatePriceTransitionV0Methods: DocumentBaseTransitionAccessors { /// Returns a reference to the `revision` field of the `DocumentUpdatePriceTransitionV0`. fn revision(&self) -> Revision; @@ -27,7 +18,7 @@ pub trait DocumentUpdatePriceTransitionV0Methods { fn set_price(&mut self, price: Credits); } -impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransitionV0 { +impl DocumentBaseTransitionAccessors for DocumentUpdatePriceTransitionV0 { fn base(&self) -> &DocumentBaseTransition { &self.base } @@ -39,7 +30,9 @@ impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransitionV0 fn set_base(&mut self, base: DocumentBaseTransition) { self.base = base; } +} +impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransitionV0 { fn revision(&self) -> Revision { self.revision } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0_methods.rs similarity index 68% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0_methods.rs index 3b605d7431..bc97724dfc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_update_price_transition/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/document_update_price_transition/v0_methods.rs @@ -1,10 +1,11 @@ use crate::fee::Credits; use crate::prelude::Revision; -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::DocumentUpdatePriceTransition; +use crate::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use crate::state_transition::batch_transition::batched_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::DocumentUpdatePriceTransition; -impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransition { +impl DocumentBaseTransitionAccessors for DocumentUpdatePriceTransition { fn base(&self) -> &DocumentBaseTransition { match self { DocumentUpdatePriceTransition::V0(v0) => &v0.base, @@ -22,7 +23,9 @@ impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransition { DocumentUpdatePriceTransition::V0(v0) => v0.base = base, } } +} +impl DocumentUpdatePriceTransitionV0Methods for DocumentUpdatePriceTransition { fn revision(&self) -> Revision { match self { DocumentUpdatePriceTransition::V0(v0) => v0.revision, 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 new file mode 100644 index 0000000000..cbd28a7d90 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/mod.rs @@ -0,0 +1,140 @@ +use bincode::{Decode, Encode}; +use derive_more::From; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +pub mod document_base_transition; +pub mod document_create_transition; +pub mod document_delete_transition; +pub mod document_purchase_transition; +pub mod document_replace_transition; +pub mod document_transfer_transition; +pub mod document_transition; +pub mod document_transition_action_type; +pub mod document_update_price_transition; +pub mod multi_party_action; +mod resolvers; +pub mod token_base_transition; +pub mod token_burn_transition; +pub mod token_destroy_frozen_funds_transition; +pub mod token_emergency_action_transition; +pub mod token_freeze_transition; +pub mod token_mint_transition; +pub mod token_transfer_transition; +pub mod token_transition; +pub mod token_transition_action_type; +pub mod token_unfreeze_transition; + +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::token_transition::TokenTransitionV0Methods; +use derive_more::Display; +pub use document_create_transition::DocumentCreateTransition; +pub use document_delete_transition::DocumentDeleteTransition; +pub use document_purchase_transition::DocumentPurchaseTransition; +pub use document_replace_transition::DocumentReplaceTransition; +pub use document_transfer_transition::DocumentTransferTransition; +use document_transition::DocumentTransition; +pub use document_update_price_transition::DocumentUpdatePriceTransition; +use platform_value::Identifier; +use token_transition::TokenTransition; + +pub const PROPERTY_ACTION: &str = "$action"; + +#[derive(Debug, Clone, Encode, Decode, From, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum BatchedTransition { + #[display("DocumentTransition({})", "_0")] + Document(DocumentTransition), + #[display("TokenTransition({})", "_0")] + Token(TokenTransition), +} + +#[derive(Debug, From, Clone, Copy, PartialEq, Display)] +pub enum BatchedTransitionRef<'a> { + #[display("DocumentTransition({})", "_0")] + Document(&'a DocumentTransition), + #[display("TokenTransition({})", "_0")] + Token(&'a TokenTransition), +} + +#[derive(Debug, From, PartialEq, Display)] +pub enum BatchedTransitionMutRef<'a> { + #[display("DocumentTransition({})", "_0")] + Document(&'a mut DocumentTransition), + #[display("TokenTransition({})", "_0")] + Token(&'a mut TokenTransition), +} + +impl<'a> BatchedTransitionRef<'a> { + pub fn to_owned_transition(&self) -> BatchedTransition { + match self { + BatchedTransitionRef::Document(doc_ref) => { + BatchedTransition::Document((*doc_ref).clone()) + } + BatchedTransitionRef::Token(tok_ref) => BatchedTransition::Token((*tok_ref).clone()), + } + } + + pub fn identity_contract_nonce(&self) -> IdentityNonce { + match self { + BatchedTransitionRef::Document(document_transition) => { + document_transition.identity_contract_nonce() + } + BatchedTransitionRef::Token(token_transition) => { + token_transition.identity_contract_nonce() + } + } + } + + pub fn data_contract_id(&self) -> Identifier { + match self { + BatchedTransitionRef::Document(document_transition) => { + document_transition.data_contract_id() + } + BatchedTransitionRef::Token(token_transition) => token_transition.data_contract_id(), + } + } +} + +impl BatchedTransition { + pub fn borrow_as_ref(&self) -> BatchedTransitionRef { + match self { + BatchedTransition::Document(doc) => { + // Create a reference to a DocumentTransition + BatchedTransitionRef::Document(doc) + } + BatchedTransition::Token(tok) => { + // Create a reference to a TokenTransition + BatchedTransitionRef::Token(tok) + } + } + } + + pub fn borrow_as_mut(&mut self) -> BatchedTransitionMutRef { + match self { + BatchedTransition::Document(doc) => { + // Create a reference to a DocumentTransition + BatchedTransitionMutRef::Document(doc) + } + BatchedTransition::Token(tok) => { + // Create a reference to a TokenTransition + BatchedTransitionMutRef::Token(tok) + } + } + } + + pub fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { + match self { + BatchedTransition::Document(document_transition) => { + document_transition.set_identity_contract_nonce(identity_contract_nonce) + } + BatchedTransition::Token(token_transition) => { + token_transition.set_identity_contract_nonce(identity_contract_nonce) + } + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs new file mode 100644 index 0000000000..52f7cf4e7f --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/multi_party_action.rs @@ -0,0 +1,5 @@ +use platform_value::Identifier; + +pub trait AllowedAsMultiPartyAction { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier; +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs new file mode 100644 index 0000000000..bf1d555544 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/resolvers.rs @@ -0,0 +1,185 @@ +use crate::state_transition::batch_transition::batched_transition::{ + BatchedTransition, BatchedTransitionRef, DocumentPurchaseTransition, DocumentTransferTransition, +}; +use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; +use crate::state_transition::batch_transition::{ + DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, + TokenBurnTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, + TokenFreezeTransition, TokenMintTransition, TokenTransferTransition, TokenUnfreezeTransition, +}; + +impl BatchTransitionResolversV0 for BatchedTransition { + fn as_transition_create(&self) -> Option<&DocumentCreateTransition> { + match self { + BatchedTransition::Document(document) => document.as_transition_create(), + BatchedTransition::Token(_) => None, + } + } + + fn as_transition_replace(&self) -> Option<&DocumentReplaceTransition> { + match self { + BatchedTransition::Document(document) => document.as_transition_replace(), + BatchedTransition::Token(_) => None, + } + } + + fn as_transition_delete(&self) -> Option<&DocumentDeleteTransition> { + match self { + BatchedTransition::Document(document) => document.as_transition_delete(), + BatchedTransition::Token(_) => None, + } + } + + fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition> { + match self { + BatchedTransition::Document(document) => document.as_transition_transfer(), + BatchedTransition::Token(_) => None, + } + } + + fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition> { + match self { + BatchedTransition::Document(document) => document.as_transition_purchase(), + BatchedTransition::Token(_) => None, + } + } + + fn as_transition_token_burn(&self) -> Option<&TokenBurnTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_burn(), + } + } + + fn as_transition_token_mint(&self) -> Option<&TokenMintTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_mint(), + } + } + + fn as_transition_token_transfer(&self) -> Option<&TokenTransferTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_transfer(), + } + } + + fn as_transition_token_freeze(&self) -> Option<&TokenFreezeTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_freeze(), + } + } + + fn as_transition_token_unfreeze(&self) -> Option<&TokenUnfreezeTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_unfreeze(), + } + } + + fn as_transition_token_destroy_frozen_funds( + &self, + ) -> Option<&TokenDestroyFrozenFundsTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_destroy_frozen_funds(), + } + } + + fn as_transition_token_emergency_action(&self) -> Option<&TokenEmergencyActionTransition> { + match self { + BatchedTransition::Document(_) => None, + BatchedTransition::Token(token) => token.as_transition_token_emergency_action(), + } + } +} + +impl<'a> BatchTransitionResolversV0 for BatchedTransitionRef<'a> { + fn as_transition_create(&self) -> Option<&DocumentCreateTransition> { + match self { + BatchedTransitionRef::Document(document) => document.as_transition_create(), + BatchedTransitionRef::Token(_) => None, + } + } + + fn as_transition_replace(&self) -> Option<&DocumentReplaceTransition> { + match self { + BatchedTransitionRef::Document(document) => document.as_transition_replace(), + BatchedTransitionRef::Token(_) => None, + } + } + + fn as_transition_delete(&self) -> Option<&DocumentDeleteTransition> { + match self { + BatchedTransitionRef::Document(document) => document.as_transition_delete(), + BatchedTransitionRef::Token(_) => None, + } + } + + fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition> { + match self { + BatchedTransitionRef::Document(document) => document.as_transition_transfer(), + BatchedTransitionRef::Token(_) => None, + } + } + + fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition> { + match self { + BatchedTransitionRef::Document(document) => document.as_transition_purchase(), + BatchedTransitionRef::Token(_) => None, + } + } + + fn as_transition_token_burn(&self) -> Option<&TokenBurnTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_burn(), + } + } + + fn as_transition_token_mint(&self) -> Option<&TokenMintTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_mint(), + } + } + + fn as_transition_token_transfer(&self) -> Option<&TokenTransferTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_transfer(), + } + } + + fn as_transition_token_freeze(&self) -> Option<&TokenFreezeTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_freeze(), + } + } + + fn as_transition_token_unfreeze(&self) -> Option<&TokenUnfreezeTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_unfreeze(), + } + } + + fn as_transition_token_destroy_frozen_funds( + &self, + ) -> Option<&TokenDestroyFrozenFundsTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_destroy_frozen_funds(), + } + } + + fn as_transition_token_emergency_action(&self) -> Option<&TokenEmergencyActionTransition> { + match self { + BatchedTransitionRef::Document(_) => None, + BatchedTransitionRef::Token(token) => token.as_transition_token_emergency_action(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs new file mode 100644 index 0000000000..02391e0be6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/fields.rs @@ -0,0 +1,12 @@ +pub(in crate::state_transition::state_transitions::document::batch_transition) mod property_names { + pub const DATA_CONTRACT_ID: &str = "$dataContractId"; + pub const TOKEN_CONTRACT_POSITION: &str = "$tokenContractPosition"; + pub const TOKEN_ID: &str = "$tokenId"; + pub const GROUP_CONTRACT_POSITION: &str = "$groupContractPosition"; + pub const GROUP_ACTION_ID: &str = "$groupActionId"; + pub const GROUP_ACTION_IS_PROPOSER: &str = "$groupActionIsProposer"; + pub const ACTION: &str = "$action"; + pub const IDENTITY_CONTRACT_NONCE: &str = "$identityContractNonce"; +} + +pub const IDENTIFIER_FIELDS: [&str; 1] = [property_names::DATA_CONTRACT_ID]; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/mod.rs new file mode 100644 index 0000000000..4b4602e72d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/mod.rs @@ -0,0 +1,106 @@ +mod fields; +pub mod token_base_transition_accessors; +pub mod v0; +mod v0_methods; + +#[cfg(any( + feature = "state-transition-value-conversion", + feature = "state-transition-json-conversion" +))] +use crate::data_contract::DataContract; +use crate::state_transition::batch_transition::document_base_transition::v0::DocumentTransitionObjectLike; +use crate::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; +#[cfg(any( + feature = "state-transition-value-conversion", + feature = "state-transition-json-conversion" +))] +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use derive_more::{Display, From}; +pub use fields::*; +#[cfg(any( + feature = "state-transition-value-conversion", + feature = "state-transition-json-conversion" +))] +use platform_value::Value; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "state-transition-json-conversion")] +use serde_json::Value as JsonValue; +#[cfg(feature = "state-transition-value-conversion")] +use std::collections::BTreeMap; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenBaseTransition { + #[display("V0({})", "_0")] + V0(TokenBaseTransitionV0), +} + +impl Default for TokenBaseTransition { + fn default() -> Self { + TokenBaseTransition::V0(TokenBaseTransitionV0::default()) // since only v0 + } +} + +impl DocumentTransitionObjectLike for TokenBaseTransition { + #[cfg(feature = "state-transition-json-conversion")] + fn from_json_object( + json_str: JsonValue, + data_contract: DataContract, + ) -> Result + where + Self: Sized, + { + let value: Value = json_str.into(); + Self::from_object(value, data_contract) + } + #[cfg(feature = "state-transition-value-conversion")] + fn from_object( + raw_transition: Value, + _data_contract: DataContract, + ) -> Result + where + Self: Sized, + { + platform_value::from_value(raw_transition).map_err(ProtocolError::ValueError) + } + #[cfg(feature = "state-transition-value-conversion")] + fn from_value_map( + map: BTreeMap, + _data_contract: DataContract, + ) -> Result + where + Self: Sized, + { + let value: Value = map.into(); + platform_value::from_value(value).map_err(ProtocolError::ValueError) + } + + #[cfg(feature = "state-transition-value-conversion")] + fn to_object(&self) -> Result { + platform_value::to_value(self).map_err(ProtocolError::ValueError) + } + #[cfg(feature = "state-transition-value-conversion")] + fn to_value_map(&self) -> Result, ProtocolError> { + let value = platform_value::to_value(self)?; + value + .into_btree_string_map() + .map_err(ProtocolError::ValueError) + } + + #[cfg(feature = "state-transition-json-conversion")] + fn to_json(&self) -> Result { + self.to_object()? + .try_into() + .map_err(ProtocolError::ValueError) + } + + #[cfg(feature = "state-transition-value-conversion")] + fn to_cleaned_object(&self) -> Result { + Ok(self.to_value_map()?.into()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/token_base_transition_accessors.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/token_base_transition_accessors.rs new file mode 100644 index 0000000000..2813dc755d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/token_base_transition_accessors.rs @@ -0,0 +1,16 @@ +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +pub trait TokenBaseTransitionAccessors { + /// Returns a reference to the `base` field of the `DocumentCreateTransitionV0`. + fn base(&self) -> &TokenBaseTransition; + + /// Returns a mut reference to the `base` field of the `DocumentCreateTransitionV0`. + fn base_mut(&mut self) -> &mut TokenBaseTransition; + + /// Sets the value of the `base` field in the `DocumentCreateTransitionV0`. + /// + /// # Arguments + /// + /// * `base` - A value of type `DocumentBaseTransition` to set. + fn set_base(&mut self, base: TokenBaseTransition); +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs new file mode 100644 index 0000000000..c3b8595dcc --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/mod.rs @@ -0,0 +1,117 @@ +pub mod v0_methods; + +#[cfg(feature = "state-transition-value-conversion")] +use std::collections::BTreeMap; + +use bincode::{Decode, Encode}; +use derive_more::Display; + +#[cfg(feature = "state-transition-value-conversion")] +use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper; +#[cfg(feature = "state-transition-value-conversion")] +use platform_value::Value; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "state-transition-value-conversion")] +use crate::data_contract::accessors::v0::DataContractV0Getters; +#[cfg(feature = "state-transition-value-conversion")] +use crate::data_contract::accessors::v1::DataContractV1Getters; +use crate::group::GroupStateTransitionInfo; +use crate::identifier::Identifier; +use crate::prelude::IdentityNonce; +#[cfg(feature = "state-transition-value-conversion")] +use crate::state_transition::batch_transition::token_base_transition::property_names; +#[cfg(feature = "state-transition-value-conversion")] +use crate::tokens::errors::TokenError; +#[cfg(any( + feature = "state-transition-json-conversion", + feature = "state-transition-value-conversion" +))] +use crate::{data_contract::DataContract, errors::ProtocolError}; + +#[derive(Debug, Clone, Encode, Decode, Default, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display( + "ID: {}, Type: {}, Contract ID: {}", + "id", + "token_id", + "data_contract_id" +)] +pub struct TokenBaseTransitionV0 { + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$identity-contract-nonce") + )] + pub identity_contract_nonce: IdentityNonce, + /// ID of the token within the contract + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$tokenContractPosition") + )] + pub token_contract_position: u16, + /// Data contract ID generated from the data contract's `owner_id` and `entropy` + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$dataContractId") + )] + pub data_contract_id: Identifier, + /// Token ID generated from the data contract ID and the token position + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$tokenId") + )] + pub token_id: Identifier, + /// Using group multi party rules for authentication + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub using_group_info: Option, +} + +impl TokenBaseTransitionV0 { + #[cfg(feature = "state-transition-value-conversion")] + pub fn from_value_map_consume( + map: &mut BTreeMap, + data_contract: DataContract, + identity_contract_nonce: IdentityNonce, + ) -> Result { + let token_contract_position = map + .remove_integer(property_names::TOKEN_CONTRACT_POSITION) + .map_err(ProtocolError::ValueError)?; + Ok(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id: Identifier::new( + map.remove_optional_hash256_bytes(property_names::DATA_CONTRACT_ID) + .map_err(ProtocolError::ValueError)? + .unwrap_or(data_contract.id().to_buffer()), + ), + token_id: map + .remove_optional_hash256_bytes(property_names::TOKEN_ID) + .map_err(ProtocolError::ValueError)? + .map(Identifier::new) + .unwrap_or(data_contract.token_id(token_contract_position).ok_or( + ProtocolError::Token(TokenError::TokenNotFoundAtPositionError.into()), + )?), + using_group_info: map + .remove_optional_integer(property_names::GROUP_CONTRACT_POSITION) + .map_err(ProtocolError::ValueError)? + .map(|group_contract_position| { + Ok::(GroupStateTransitionInfo { + group_contract_position, + action_id: map + .remove_hash256_bytes(property_names::GROUP_ACTION_ID) + .map_err(ProtocolError::ValueError)? + .into(), + action_is_proposer: map + .remove_bool(property_names::GROUP_ACTION_IS_PROPOSER) + .map_err(ProtocolError::ValueError)?, + }) + }) + .transpose()?, + }) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..40369689bd --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0/v0_methods.rs @@ -0,0 +1,102 @@ +use crate::data_contract::GroupContractPosition; +use crate::group::GroupStateTransitionInfo; +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; +use crate::tokens::calculate_token_id; +use platform_value::Identifier; + +/// A trait that contains getter and setter methods for `TokenBaseTransitionV0` +pub trait TokenBaseTransitionV0Methods { + /// Returns the document type name. + fn token_contract_position(&self) -> u16; + + /// Sets the token id. + fn set_token_contract_position(&mut self, token_id: u16); + + /// Returns the data contract ID. + fn data_contract_id(&self) -> Identifier; + fn data_contract_id_ref(&self) -> &Identifier; + + /// Calculates the token ID. + fn calculate_token_id(&self) -> Identifier { + calculate_token_id( + self.data_contract_id().as_bytes(), + self.token_contract_position(), + ) + .into() + } + + /// Returns the token ID. + fn token_id(&self) -> Identifier; + fn token_id_ref(&self) -> &Identifier; + + fn set_token_id(&mut self, token_id: Identifier); + + /// Returns the group ID. + fn group_position(&self) -> Option; + + fn using_group_info(&self) -> Option; + + fn set_using_group_info(&mut self, group_info: Option); + + /// Sets the data contract ID. + fn set_data_contract_id(&mut self, data_contract_id: Identifier); + fn identity_contract_nonce(&self) -> IdentityNonce; + fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce); +} + +impl TokenBaseTransitionV0Methods for TokenBaseTransitionV0 { + fn token_contract_position(&self) -> u16 { + self.token_contract_position + } + + fn set_token_contract_position(&mut self, token_contract_position: u16) { + self.token_contract_position = token_contract_position; + } + + fn data_contract_id(&self) -> Identifier { + self.data_contract_id + } + + fn data_contract_id_ref(&self) -> &Identifier { + &self.data_contract_id + } + + fn token_id(&self) -> Identifier { + self.token_id + } + + fn token_id_ref(&self) -> &Identifier { + &self.token_id + } + + fn set_data_contract_id(&mut self, data_contract_id: Identifier) { + self.data_contract_id = data_contract_id; + } + + fn set_token_id(&mut self, token_id: Identifier) { + self.token_id = token_id; + } + + fn identity_contract_nonce(&self) -> IdentityNonce { + self.identity_contract_nonce + } + + fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { + self.identity_contract_nonce = identity_contract_nonce; + } + + fn group_position(&self) -> Option { + self.using_group_info + .as_ref() + .map(|info| info.group_contract_position) + } + + fn set_using_group_info(&mut self, group_info: Option) { + self.using_group_info = group_info; + } + + fn using_group_info(&self) -> Option { + self.using_group_info + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs new file mode 100644 index 0000000000..5eeffbf6ff --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_base_transition/v0_methods.rs @@ -0,0 +1,86 @@ +use crate::data_contract::GroupContractPosition; +use crate::group::GroupStateTransitionInfo; +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use platform_value::Identifier; + +impl TokenBaseTransitionV0Methods for TokenBaseTransition { + fn token_contract_position(&self) -> u16 { + match self { + TokenBaseTransition::V0(v0) => v0.token_contract_position(), + } + } + + fn set_token_contract_position(&mut self, token_id: u16) { + match self { + TokenBaseTransition::V0(v0) => v0.set_token_contract_position(token_id), + } + } + + fn data_contract_id(&self) -> Identifier { + match self { + TokenBaseTransition::V0(v0) => v0.data_contract_id(), + } + } + + fn data_contract_id_ref(&self) -> &Identifier { + match self { + TokenBaseTransition::V0(v0) => v0.data_contract_id_ref(), + } + } + + fn token_id(&self) -> Identifier { + match self { + TokenBaseTransition::V0(v0) => v0.token_id(), + } + } + + fn token_id_ref(&self) -> &Identifier { + match self { + TokenBaseTransition::V0(v0) => v0.token_id_ref(), + } + } + + fn set_token_id(&mut self, token_id: Identifier) { + match self { + TokenBaseTransition::V0(v0) => v0.set_token_id(token_id), + } + } + + fn group_position(&self) -> Option { + match self { + TokenBaseTransition::V0(v0) => v0.group_position(), + } + } + + fn using_group_info(&self) -> Option { + match self { + TokenBaseTransition::V0(v0) => v0.using_group_info(), + } + } + + fn set_using_group_info(&mut self, group_info: Option) { + match self { + TokenBaseTransition::V0(v0) => v0.set_using_group_info(group_info), + } + } + + fn set_data_contract_id(&mut self, data_contract_id: Identifier) { + match self { + TokenBaseTransition::V0(v0) => v0.set_data_contract_id(data_contract_id), + } + } + + fn identity_contract_nonce(&self) -> IdentityNonce { + match self { + TokenBaseTransition::V0(v0) => v0.identity_contract_nonce, + } + } + + fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { + match self { + TokenBaseTransition::V0(v0) => v0.identity_contract_nonce = identity_contract_nonce, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/mod.rs new file mode 100644 index 0000000000..5c07e9a97d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/mod.rs @@ -0,0 +1,24 @@ +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::TokenBurnTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenBurnTransition { + #[display("V0({})", "_0")] + V0(TokenBurnTransitionV0), +} + +impl Default for TokenBurnTransition { + fn default() -> Self { + TokenBurnTransition::V0(TokenBurnTransitionV0::default()) // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/mod.rs new file mode 100644 index 0000000000..dc07a53827 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/mod.rs @@ -0,0 +1,38 @@ +pub mod v0_methods; + +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}; + +mod property_names { + pub const AMOUNT: &str = "$amount"; +} +/// The Identifier fields in [`TokenBurnTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; + +#[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}, Amount: {burn_amount}")] +pub struct TokenBurnTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "burnAmount") + )] + /// How much should we burn + pub burn_amount: u64, + /// The public note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "publicNote") + )] + pub public_note: Option, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..8cdcd6e153 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0/v0_methods.rs @@ -0,0 +1,76 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_burn_transition::TokenBurnTransitionV0; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenBurnTransitionV0 { + fn base(&self) -> &TokenBaseTransition { + &self.base + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + &mut self.base + } + + fn set_base(&mut self, base: TokenBaseTransition) { + self.base = base; + } +} + +pub trait TokenBurnTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + fn burn_amount(&self) -> u64; + + fn set_burn_amount(&mut self, amount: u64); + + /// Returns the `public_note` field of the `TokenBurnTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenBurnTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the `public_note` field in the `TokenBurnTransitionV0`. + fn set_public_note(&mut self, public_note: Option); +} + +impl TokenBurnTransitionV0Methods for TokenBurnTransitionV0 { + fn burn_amount(&self) -> u64 { + self.burn_amount + } + + fn set_burn_amount(&mut self, amount: u64) { + self.burn_amount = amount; + } + + 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 TokenBurnTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenBurnTransitionV0 { + base, burn_amount, .. + } = self; + + let mut bytes = b"action_token_burn".to_vec(); + bytes.extend_from_slice(base.token_id().as_bytes()); + bytes.extend_from_slice(owner_id.as_bytes()); + bytes.extend_from_slice(&base.identity_contract_nonce().to_be_bytes()); + bytes.extend_from_slice(&burn_amount.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs new file mode 100644 index 0000000000..060ac9c70b --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_burn_transition/v0_methods.rs @@ -0,0 +1,66 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::state_transition::batch_transition::token_burn_transition::TokenBurnTransition; +use crate::state_transition::batch_transition::token_burn_transition::v0::v0_methods::TokenBurnTransitionV0Methods; + +impl TokenBaseTransitionAccessors for TokenBurnTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenBurnTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenBurnTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenBurnTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenBurnTransitionV0Methods for TokenBurnTransition { + fn burn_amount(&self) -> u64 { + match self { + TokenBurnTransition::V0(v0) => v0.burn_amount(), + } + } + + fn set_burn_amount(&mut self, burn_amount: u64) { + match self { + TokenBurnTransition::V0(v0) => v0.set_burn_amount(burn_amount), + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenBurnTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenBurnTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenBurnTransition::V0(v0) => v0.set_public_note(public_note), + } + } +} + +impl AllowedAsMultiPartyAction for TokenBurnTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenBurnTransition::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_destroy_frozen_funds_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/mod.rs new file mode 100644 index 0000000000..5d1cd01d77 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_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::TokenDestroyFrozenFundsTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenDestroyFrozenFundsTransition { + #[display("V0({})", "_0")] + V0(TokenDestroyFrozenFundsTransitionV0), +} + +impl Default for TokenDestroyFrozenFundsTransition { + fn default() -> Self { + TokenDestroyFrozenFundsTransition::V0(TokenDestroyFrozenFundsTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/mod.rs new file mode 100644 index 0000000000..251ff82191 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/mod.rs @@ -0,0 +1,25 @@ +pub mod v0_methods; + +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode::{Decode, Encode}; +use derive_more::Display; +use platform_value::Identifier; +#[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}, Destroyed Account Identity ID: {frozen_identity_id}")] +pub struct TokenDestroyFrozenFundsTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + /// The identity id of the account whose balance should be destroyed + pub frozen_identity_id: Identifier, + /// The public note + pub public_note: Option, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..ef6015a341 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0/v0_methods.rs @@ -0,0 +1,78 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransitionV0; +use crate::state_transition::batch_transition::TokenDestroyFrozenFundsTransition; + +impl TokenBaseTransitionAccessors for TokenDestroyFrozenFundsTransitionV0 { + 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 TokenDestroyFrozenFundsTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + /// Returns the `public_note` field of the `TokenDestroyFrozenFundsTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenDestroyFrozenFundsTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the `public_note` field in the `TokenDestroyFrozenFundsTransitionV0`. + fn set_public_note(&mut self, public_note: Option); + + /// Returns the `frozen_identity_id` field of the `TokenFreezeTransitionV0`. + fn frozen_identity_id(&self) -> Identifier; + + /// Sets the value of the `frozen_identity_id` field in the `TokenFreezeTransitionV0`. + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier); +} + +impl TokenDestroyFrozenFundsTransitionV0Methods for TokenDestroyFrozenFundsTransitionV0 { + 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; + } + + fn frozen_identity_id(&self) -> Identifier { + self.frozen_identity_id + } + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + self.frozen_identity_id = frozen_identity_id; + } +} + +impl AllowedAsMultiPartyAction for TokenDestroyFrozenFundsTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenDestroyFrozenFundsTransitionV0 { + base, + frozen_identity_id, + .. + } = self; + + TokenDestroyFrozenFundsTransition::calculate_action_id_with_fields( + base.token_id().as_bytes(), + owner_id.as_bytes(), + frozen_identity_id.as_bytes(), + base.identity_contract_nonce(), + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0_methods.rs new file mode 100644 index 0000000000..73582b9c97 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_destroy_frozen_funds_transition/v0_methods.rs @@ -0,0 +1,87 @@ +use platform_value::Identifier; +use crate::prelude::IdentityNonce; +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_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransition; +use crate::state_transition::batch_transition::token_destroy_frozen_funds_transition::v0::v0_methods::TokenDestroyFrozenFundsTransitionV0Methods; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenDestroyFrozenFundsTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenDestroyFrozenFundsTransitionV0Methods for TokenDestroyFrozenFundsTransition { + fn public_note(&self) -> Option<&String> { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => v0.set_public_note(public_note), + } + } + + fn frozen_identity_id(&self) -> Identifier { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => v0.frozen_identity_id(), + } + } + + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => { + v0.set_frozen_identity_id(frozen_identity_id) + } + } + } +} + +impl AllowedAsMultiPartyAction for TokenDestroyFrozenFundsTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenDestroyFrozenFundsTransition::V0(v0) => v0.calculate_action_id(owner_id), + } + } +} + +impl TokenDestroyFrozenFundsTransition { + pub fn calculate_action_id_with_fields( + token_id: &[u8; 32], + owner_id: &[u8; 32], + target_id: &[u8; 32], + identity_contract_nonce: IdentityNonce, + ) -> Identifier { + let mut bytes = b"action_token_destroy".to_vec(); + bytes.extend_from_slice(token_id); + bytes.extend_from_slice(owner_id); + bytes.extend_from_slice(target_id); + bytes.extend_from_slice(&identity_contract_nonce.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/mod.rs new file mode 100644 index 0000000000..b338e9e75e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_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::TokenEmergencyActionTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenEmergencyActionTransition { + #[display("V0({})", "_0")] + V0(TokenEmergencyActionTransitionV0), +} + +impl Default for TokenEmergencyActionTransition { + fn default() -> Self { + TokenEmergencyActionTransition::V0(TokenEmergencyActionTransitionV0::default()) + // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/mod.rs new file mode 100644 index 0000000000..18ea3f89b6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/mod.rs @@ -0,0 +1,30 @@ +pub mod v0_methods; + +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::tokens::emergency_action::TokenEmergencyAction; +use bincode::{Decode, Encode}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct TokenEmergencyActionTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + /// The emergency action + pub emergency_action: TokenEmergencyAction, + /// The public note + pub public_note: Option, +} + +impl fmt::Display for TokenEmergencyActionTransitionV0 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Base: {}", self.base) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..4f0e17f2c4 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0/v0_methods.rs @@ -0,0 +1,80 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::batched_transition::token_emergency_action_transition::TokenEmergencyActionTransitionV0; +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::TokenEmergencyActionTransition; +use crate::tokens::emergency_action::TokenEmergencyAction; + +impl TokenBaseTransitionAccessors for TokenEmergencyActionTransitionV0 { + 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 TokenEmergencyActionTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + /// Returns the `public_note` field of the `TokenEmergencyActionTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenEmergencyActionTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the value of the `public_note` field in the `TokenEmergencyActionTransitionV0`. + fn set_public_note(&mut self, public_note: Option); + + /// Returns the `emergency_action` field of the `TokenEmergencyActionTransitionV0`. + fn emergency_action(&self) -> TokenEmergencyAction; + + /// Sets the value of the `emergency_action` field in the `TokenEmergencyActionTransitionV0`. + fn set_emergency_action(&mut self, emergency_action: TokenEmergencyAction); +} + +impl TokenEmergencyActionTransitionV0Methods for TokenEmergencyActionTransitionV0 { + 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; + } + + fn emergency_action(&self) -> TokenEmergencyAction { + self.emergency_action + } + + fn set_emergency_action(&mut self, emergency_action: TokenEmergencyAction) { + self.emergency_action = emergency_action; + } +} + +impl AllowedAsMultiPartyAction for TokenEmergencyActionTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenEmergencyActionTransitionV0 { + base, + emergency_action, + .. + } = self; + + TokenEmergencyActionTransition::calculate_action_id_with_fields( + base.token_id().as_bytes(), + owner_id.as_bytes(), + *emergency_action, + base.identity_contract_nonce(), + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0_methods.rs new file mode 100644 index 0000000000..e089d2f8de --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_emergency_action_transition/v0_methods.rs @@ -0,0 +1,86 @@ +use platform_value::Identifier; +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::batched_transition::token_emergency_action_transition::v0::v0_methods::TokenEmergencyActionTransitionV0Methods; +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::TokenEmergencyActionTransition; +use crate::tokens::emergency_action::TokenEmergencyAction; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenEmergencyActionTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenEmergencyActionTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenEmergencyActionTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenEmergencyActionTransitionV0Methods for TokenEmergencyActionTransition { + fn public_note(&self) -> Option<&String> { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.set_public_note(public_note), + } + } + + fn emergency_action(&self) -> TokenEmergencyAction { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.emergency_action(), + } + } + + fn set_emergency_action(&mut self, emergency_action: TokenEmergencyAction) { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.set_emergency_action(emergency_action), + } + } +} + +impl AllowedAsMultiPartyAction for TokenEmergencyActionTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenEmergencyActionTransition::V0(v0) => v0.calculate_action_id(owner_id), + } + } +} + +impl TokenEmergencyActionTransition { + pub fn calculate_action_id_with_fields( + token_id: &[u8; 32], + owner_id: &[u8; 32], + emergency_action: TokenEmergencyAction, + identity_contract_nonce: IdentityNonce, + ) -> Identifier { + let mut bytes = b"action_token_emergency_action".to_vec(); + bytes.extend_from_slice(token_id); + bytes.extend_from_slice(owner_id); + bytes.extend_from_slice(&[emergency_action as u8]); + bytes.extend_from_slice(&identity_contract_nonce.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/mod.rs new file mode 100644 index 0000000000..844454a661 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/mod.rs @@ -0,0 +1,24 @@ +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::TokenFreezeTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenFreezeTransition { + #[display("V0({})", "_0")] + V0(TokenFreezeTransitionV0), +} + +impl Default for TokenFreezeTransition { + fn default() -> Self { + TokenFreezeTransition::V0(TokenFreezeTransitionV0::default()) // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/mod.rs new file mode 100644 index 0000000000..c27da67974 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/mod.rs @@ -0,0 +1,45 @@ +pub mod v0_methods; + +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode::{Decode, Encode}; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use std::fmt; + +mod property_names { + pub const AMOUNT: &str = "$amount"; +} +/// The Identifier fields in [`TokenFreezeTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct TokenFreezeTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + /// The identity that we are freezing + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "frozenIdentityId") + )] + pub frozen_identity_id: Identifier, + /// The public note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "publicNote") + )] + pub public_note: Option, +} + +impl fmt::Display for TokenFreezeTransitionV0 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Format the base transition (assuming `TokenBaseTransition` implements Display) + write!(f, "Base: {}, Froze: {}", self.base, self.frozen_identity_id) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..bec3466b7b --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0/v0_methods.rs @@ -0,0 +1,78 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_freeze_transition::TokenFreezeTransitionV0; +use crate::state_transition::batch_transition::TokenFreezeTransition; + +impl TokenBaseTransitionAccessors for TokenFreezeTransitionV0 { + 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 TokenFreezeTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + /// Returns the `public_note` field of the `TokenFreezeTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenFreezeTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the value of the `public_note` field in the `TokenFreezeTransitionV0`. + fn set_public_note(&mut self, public_note: Option); + + /// Returns the `frozen_identity_id` field of the `TokenFreezeTransitionV0`. + fn frozen_identity_id(&self) -> Identifier; + + /// Sets the value of the `frozen_identity_id` field in the `TokenFreezeTransitionV0`. + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier); +} + +impl TokenFreezeTransitionV0Methods for TokenFreezeTransitionV0 { + 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; + } + + fn frozen_identity_id(&self) -> Identifier { + self.frozen_identity_id + } + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + self.frozen_identity_id = frozen_identity_id; + } +} + +impl AllowedAsMultiPartyAction for TokenFreezeTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenFreezeTransitionV0 { + base, + frozen_identity_id, + .. + } = self; + + TokenFreezeTransition::calculate_action_id_with_fields( + base.token_id().as_bytes(), + owner_id.as_bytes(), + frozen_identity_id.as_bytes(), + base.identity_contract_nonce(), + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0_methods.rs new file mode 100644 index 0000000000..13c06dcd45 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_freeze_transition/v0_methods.rs @@ -0,0 +1,85 @@ +use platform_value::Identifier; +use crate::prelude::IdentityNonce; +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_freeze_transition::v0::v0_methods::TokenFreezeTransitionV0Methods; +use crate::state_transition::batch_transition::TokenFreezeTransition; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenFreezeTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenFreezeTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenFreezeTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenFreezeTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenFreezeTransitionV0Methods for TokenFreezeTransition { + fn public_note(&self) -> Option<&String> { + match self { + TokenFreezeTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenFreezeTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenFreezeTransition::V0(v0) => v0.set_public_note(public_note), + } + } + + fn frozen_identity_id(&self) -> Identifier { + match self { + TokenFreezeTransition::V0(v0) => v0.frozen_identity_id(), + } + } + + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + match self { + TokenFreezeTransition::V0(v0) => v0.set_frozen_identity_id(frozen_identity_id), + } + } +} + +impl AllowedAsMultiPartyAction for TokenFreezeTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenFreezeTransition::V0(v0) => v0.calculate_action_id(owner_id), + } + } +} + +impl TokenFreezeTransition { + pub fn calculate_action_id_with_fields( + token_id: &[u8; 32], + owner_id: &[u8; 32], + target_id: &[u8; 32], + identity_contract_nonce: IdentityNonce, + ) -> Identifier { + let mut bytes = b"action_token_freeze".to_vec(); + bytes.extend_from_slice(token_id); + bytes.extend_from_slice(owner_id); + bytes.extend_from_slice(target_id); + bytes.extend_from_slice(&identity_contract_nonce.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/mod.rs new file mode 100644 index 0000000000..a37fe199c3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/mod.rs @@ -0,0 +1,24 @@ +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::TokenMintTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenMintTransition { + #[display("V0({})", "_0")] + V0(TokenMintTransitionV0), +} + +impl Default for TokenMintTransition { + fn default() -> Self { + TokenMintTransition::V0(TokenMintTransitionV0::default()) // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/mod.rs new file mode 100644 index 0000000000..da8079655a --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/mod.rs @@ -0,0 +1,59 @@ +pub mod v0_methods; + +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode::{Decode, Encode}; +use platform_value::string_encoding::Encoding; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use std::fmt; + +mod property_names { + pub const AMOUNT: &str = "$amount"; +} +/// The Identifier fields in [`TokenMintTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct TokenMintTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "issuedToIdentityId") + )] + /// Who should we issue the token to? If this is not set then we issue to the identity set in + /// contract settings. If such an operation is allowed. + pub issued_to_identity_id: Option, + + /// How much should we issue + pub amount: u64, + /// The public note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "publicNote") + )] + pub public_note: Option, +} + +impl fmt::Display for TokenMintTransitionV0 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Format the base transition (assuming `TokenBaseTransition` implements Display) + write!( + f, + "Base: {}, Amount: {}, To: {}", + self.base, // Assuming `TokenBaseTransition` implements `Display` + self.amount, + self.issued_to_identity_id + .as_ref() + .map_or("(Identity Set By Contract)".to_string(), |id| id + .to_string(Encoding::Base58)) + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..9bb315fd6e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0/v0_methods.rs @@ -0,0 +1,86 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_mint_transition::TokenMintTransitionV0; +use crate::state_transition::batch_transition::TokenMintTransition; + +impl TokenBaseTransitionAccessors for TokenMintTransitionV0 { + 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 TokenMintTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + fn amount(&self) -> u64; + + fn set_amount(&mut self, amount: u64); + + /// Returns the `public_note` field of the `TokenMintTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenMintTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the value of the `public_note` field in the `TokenMintTransitionV0`. + fn set_public_note(&mut self, public_note: Option); + + /// Returns the `issued_to_identity_id` field of the `TokenMintTransitionV0`. + fn issued_to_identity_id(&self) -> Option; + + /// Sets the value of the `issued_to_identity_id` field in the `TokenMintTransitionV0`. + fn set_issued_to_identity_id(&mut self, issued_to_identity_id: Option); +} + +impl TokenMintTransitionV0Methods for TokenMintTransitionV0 { + fn amount(&self) -> u64 { + self.amount + } + + fn set_amount(&mut self, amount: u64) { + self.amount = amount; + } + + 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; + } + + fn issued_to_identity_id(&self) -> Option { + self.issued_to_identity_id + } + fn set_issued_to_identity_id(&mut self, issued_to_identity_id: Option) { + self.issued_to_identity_id = issued_to_identity_id; + } +} + +impl AllowedAsMultiPartyAction for TokenMintTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenMintTransitionV0 { base, amount, .. } = self; + + TokenMintTransition::calculate_action_id_with_fields( + base.token_id().as_bytes(), + owner_id.as_bytes(), + base.identity_contract_nonce(), + *amount, + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0_methods.rs new file mode 100644 index 0000000000..245242e452 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_mint_transition/v0_methods.rs @@ -0,0 +1,98 @@ +use platform_value::Identifier; +use crate::balances::credits::TokenAmount; +use crate::prelude::IdentityNonce; +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_mint_transition::TokenMintTransition; +use crate::state_transition::batch_transition::token_mint_transition::v0::v0_methods::TokenMintTransitionV0Methods; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenMintTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenMintTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenMintTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenMintTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenMintTransitionV0Methods for TokenMintTransition { + fn amount(&self) -> u64 { + match self { + TokenMintTransition::V0(v0) => v0.amount(), + } + } + + fn set_amount(&mut self, amount: u64) { + match self { + TokenMintTransition::V0(v0) => v0.set_amount(amount), + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenMintTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenMintTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenMintTransition::V0(v0) => v0.set_public_note(public_note), + } + } + + fn issued_to_identity_id(&self) -> Option { + match self { + TokenMintTransition::V0(v0) => v0.issued_to_identity_id(), + } + } + + fn set_issued_to_identity_id(&mut self, issued_to_identity_id: Option) { + match self { + TokenMintTransition::V0(v0) => v0.set_issued_to_identity_id(issued_to_identity_id), + } + } +} + +impl AllowedAsMultiPartyAction for TokenMintTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenMintTransition::V0(v0) => v0.calculate_action_id(owner_id), + } + } +} + +impl TokenMintTransition { + pub fn calculate_action_id_with_fields( + token_id: &[u8; 32], + owner_id: &[u8; 32], + identity_contract_nonce: IdentityNonce, + mint_amount: TokenAmount, + ) -> Identifier { + let mut bytes = b"action_token_mint".to_vec(); + bytes.extend_from_slice(token_id); + bytes.extend_from_slice(owner_id); + bytes.extend_from_slice(&identity_contract_nonce.to_be_bytes()); + bytes.extend_from_slice(&mint_amount.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/mod.rs new file mode 100644 index 0000000000..39c8a54695 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/mod.rs @@ -0,0 +1,18 @@ +pub mod v0; +pub 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::*; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenTransferTransition { + #[display("V0({})", "_0")] + V0(TokenTransferTransitionV0), +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/mod.rs new file mode 100644 index 0000000000..0f3da97343 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/mod.rs @@ -0,0 +1,67 @@ +pub mod v0_methods; + +use bincode::{Decode, Encode}; +use derive_more::Display; + +pub use super::super::token_base_transition::IDENTIFIER_FIELDS; +use crate::prelude::{ + DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex, +}; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +mod property_names { + pub const AMOUNT: &str = "$amount"; + pub const RECIPIENT_OWNER_ID: &str = "recipientOwnerId"; +} + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[display( + "Base: {}, Amount: {}, Recipient: {:?}", + "base", + "amount", + "recipient_owner_id" +)] +pub struct TokenTransferTransitionV0 { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "$amount") + )] + pub amount: u64, + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "recipientId") + )] + pub recipient_id: Identifier, + /// The public note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "publicNote") + )] + pub public_note: Option, + /// An optional shared encrypted note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "sharedEncryptedNote") + )] + pub shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + /// An optional private encrypted note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "privateEncryptedNote") + )] + pub private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..ec31b70b1c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0/v0_methods.rs @@ -0,0 +1,195 @@ +use platform_value::Identifier; +use crate::prelude::{DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex}; +use crate::state_transition::batch_transition::batched_transition::token_transfer_transition::TokenTransferTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenTransferTransitionV0 { + 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 TokenTransferTransitionV0Methods: TokenBaseTransitionAccessors { + /// Returns the `amount` field of the `TokenTransferTransitionV0`. + fn amount(&self) -> u64; + + /// Sets the value of the `amount` field in the `TokenTransferTransitionV0`. + fn set_amount(&mut self, amount: u64); + + /// Returns the `recipient_owner_id` field of the `TokenTransferTransitionV0`. + fn recipient_id(&self) -> Identifier; + + /// Returns a reference to the `recipient_owner_id` field of the `TokenTransferTransitionV0`. + fn recipient_id_ref(&self) -> &Identifier; + + /// Sets the value of the `recipient_owner_id` field in the `TokenTransferTransitionV0`. + fn set_recipient_id(&mut self, recipient_owner_id: Identifier); + + /// Returns the `public_note` field of the `TokenTransferTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenTransferTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the value of the `public_note` field in the `TokenTransferTransitionV0`. + fn set_public_note(&mut self, public_note: Option); + + /// Returns the `shared_encrypted_note` field of the `TokenTransferTransitionV0`. + fn shared_encrypted_note(&self) -> Option<&(SenderKeyIndex, RecipientKeyIndex, Vec)>; + + /// Returns the owned `shared_encrypted_note` field of the `TokenTransferTransitionV0`. + fn shared_encrypted_note_owned(self) -> Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>; + + /// Sets the value of the `shared_encrypted_note` field in the `TokenTransferTransitionV0`. + fn set_shared_encrypted_note( + &mut self, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + ); + + /// Returns the `private_encrypted_note` field of the `TokenTransferTransitionV0`. + fn private_encrypted_note( + &self, + ) -> Option<&( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>; + + /// Returns the owned `private_encrypted_note` field of the `TokenTransferTransitionV0`. + fn private_encrypted_note_owned( + self, + ) -> Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>; + + /// Sets the value of the `private_encrypted_note` field in the `TokenTransferTransitionV0`. + fn set_private_encrypted_note( + &mut self, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ); + + /// Returns all notes (public, shared, and private) as owned values in a tuple. + fn notes_owned( + self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ); +} + +impl TokenTransferTransitionV0Methods for TokenTransferTransitionV0 { + fn amount(&self) -> u64 { + self.amount + } + + fn set_amount(&mut self, amount: u64) { + self.amount = amount; + } + + fn recipient_id(&self) -> Identifier { + self.recipient_id + } + + fn recipient_id_ref(&self) -> &Identifier { + &self.recipient_id + } + + fn set_recipient_id(&mut self, recipient_owner_id: Identifier) { + self.recipient_id = recipient_owner_id; + } + 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; + } + + fn shared_encrypted_note(&self) -> Option<&(SenderKeyIndex, RecipientKeyIndex, Vec)> { + self.shared_encrypted_note.as_ref() + } + + fn shared_encrypted_note_owned(self) -> Option<(SenderKeyIndex, RecipientKeyIndex, Vec)> { + self.shared_encrypted_note + } + + fn set_shared_encrypted_note( + &mut self, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + ) { + self.shared_encrypted_note = shared_encrypted_note; + } + + fn private_encrypted_note( + &self, + ) -> Option<&( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + self.private_encrypted_note.as_ref() + } + + fn private_encrypted_note_owned( + self, + ) -> Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + self.private_encrypted_note + } + + fn set_private_encrypted_note( + &mut self, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + self.private_encrypted_note = private_encrypted_note; + } + + fn notes_owned( + self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + ( + self.public_note, + self.shared_encrypted_note, + self.private_encrypted_note, + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0_methods.rs new file mode 100644 index 0000000000..414e53f5d4 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transfer_transition/v0_methods.rs @@ -0,0 +1,156 @@ +use platform_value::Identifier; +use crate::prelude::{DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex}; +use crate::state_transition::batch_transition::batched_transition::token_transfer_transition::v0::v0_methods::TokenTransferTransitionV0Methods; +use crate::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; +use crate::state_transition::batch_transition::TokenTransferTransition; +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; + +impl TokenBaseTransitionAccessors for TokenTransferTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenTransferTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenTransferTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenTransferTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenTransferTransitionV0Methods for TokenTransferTransition { + fn amount(&self) -> u64 { + match self { + TokenTransferTransition::V0(v0) => v0.amount, + } + } + + fn set_amount(&mut self, amount: u64) { + match self { + TokenTransferTransition::V0(v0) => v0.amount = amount, + } + } + + fn recipient_id(&self) -> Identifier { + match self { + TokenTransferTransition::V0(v0) => v0.recipient_id, + } + } + + fn recipient_id_ref(&self) -> &Identifier { + match self { + TokenTransferTransition::V0(v0) => &v0.recipient_id, + } + } + + fn set_recipient_id(&mut self, recipient_id: Identifier) { + match self { + TokenTransferTransition::V0(v0) => v0.recipient_id = recipient_id, + } + } + + // Methods for `public_note` + fn public_note(&self) -> Option<&String> { + match self { + TokenTransferTransition::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenTransferTransition::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenTransferTransition::V0(v0) => v0.public_note = public_note, + } + } + + fn shared_encrypted_note(&self) -> Option<&(SenderKeyIndex, RecipientKeyIndex, Vec)> { + match self { + TokenTransferTransition::V0(v0) => v0.shared_encrypted_note.as_ref(), + } + } + + fn shared_encrypted_note_owned(self) -> Option<(SenderKeyIndex, RecipientKeyIndex, Vec)> { + match self { + TokenTransferTransition::V0(v0) => v0.shared_encrypted_note, + } + } + + fn set_shared_encrypted_note( + &mut self, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + ) { + match self { + TokenTransferTransition::V0(v0) => v0.shared_encrypted_note = shared_encrypted_note, + } + } + + fn private_encrypted_note( + &self, + ) -> Option<&( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + match self { + TokenTransferTransition::V0(v0) => v0.private_encrypted_note.as_ref(), + } + } + + fn private_encrypted_note_owned( + self, + ) -> Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + match self { + TokenTransferTransition::V0(v0) => v0.private_encrypted_note, + } + } + + fn set_private_encrypted_note( + &mut self, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + match self { + TokenTransferTransition::V0(v0) => v0.private_encrypted_note = private_encrypted_note, + } + } + + // Method to return all notes as owned values + fn notes_owned( + self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + match self { + TokenTransferTransition::V0(v0) => ( + v0.public_note, + v0.shared_encrypted_note, + v0.private_encrypted_note, + ), + } + } +} 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 new file mode 100644 index 0000000000..0ca461a184 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition.rs @@ -0,0 +1,218 @@ +use derive_more::{Display, From}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use platform_value::Identifier; +use bincode::{Encode, Decode}; +use crate::prelude::IdentityNonce; +use crate::state_transition::batch_transition::{DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, TokenBurnTransition, 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; +use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; +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; + +#[derive(Debug, Clone, Encode, Decode, From, PartialEq, Display)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenTransition { + #[display("TokenBurnTransition({})", "_0")] + Burn(TokenBurnTransition), + + #[display("TokenIssuanceTransition({})", "_0")] + Mint(TokenMintTransition), + + #[display("TokenTransferTransition({})", "_0")] + Transfer(TokenTransferTransition), + + #[display("TokenFreezeTransition({})", "_0")] + Freeze(TokenFreezeTransition), + + #[display("TokenUnfreezeTransition({})", "_0")] + Unfreeze(TokenUnfreezeTransition), + + #[display("TokenDestroyFrozenFundsTransition({})", "_0")] + DestroyFrozenFunds(TokenDestroyFrozenFundsTransition), + + #[display("TokenEmergencyActionTransition({})", "_0")] + EmergencyAction(TokenEmergencyActionTransition), +} + +impl BatchTransitionResolversV0 for TokenTransition { + fn as_transition_create(&self) -> Option<&DocumentCreateTransition> { + None + } + fn as_transition_replace(&self) -> Option<&DocumentReplaceTransition> { + None + } + + fn as_transition_delete(&self) -> Option<&DocumentDeleteTransition> { + None + } + + fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition> { + None + } + + fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition> { + None + } + + fn as_transition_token_burn(&self) -> Option<&TokenBurnTransition> { + if let Self::Burn(ref t) = self { + Some(t) + } else { + None + } + } + fn as_transition_token_mint(&self) -> Option<&TokenMintTransition> { + if let Self::Mint(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_transfer(&self) -> Option<&TokenTransferTransition> { + if let Self::Transfer(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_freeze(&self) -> Option<&TokenFreezeTransition> { + if let Self::Freeze(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_unfreeze(&self) -> Option<&TokenUnfreezeTransition> { + if let Self::Unfreeze(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_destroy_frozen_funds( + &self, + ) -> Option<&TokenDestroyFrozenFundsTransition> { + if let Self::DestroyFrozenFunds(ref t) = self { + Some(t) + } else { + None + } + } + + fn as_transition_token_emergency_action(&self) -> Option<&TokenEmergencyActionTransition> { + if let Self::EmergencyAction(ref t) = self { + Some(t) + } else { + None + } + } +} + +pub trait TokenTransitionV0Methods { + fn base(&self) -> &TokenBaseTransition; + fn base_mut(&mut self) -> &mut TokenBaseTransition; + /// get the data contract ID + fn data_contract_id(&self) -> Identifier; + /// set data contract's ID + fn set_data_contract_id(&mut self, id: Identifier); + + /// get the token ID + fn token_id(&self) -> Identifier; + + /// set the token ID + fn set_token_id(&mut self, id: Identifier); + + /// get the identity contract nonce + fn identity_contract_nonce(&self) -> IdentityNonce; + /// sets identity contract nonce + fn set_identity_contract_nonce(&mut self, nonce: IdentityNonce); + + fn calculate_action_id(&self, owner_id: Identifier) -> Option; + + fn can_calculate_action_id(&self) -> bool; +} + +impl TokenTransitionV0Methods for TokenTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenTransition::Burn(t) => t.base(), + TokenTransition::Mint(t) => t.base(), + TokenTransition::Transfer(t) => t.base(), + TokenTransition::Freeze(t) => t.base(), + TokenTransition::Unfreeze(t) => t.base(), + TokenTransition::DestroyFrozenFunds(t) => t.base(), + TokenTransition::EmergencyAction(t) => t.base(), + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenTransition::Burn(t) => t.base_mut(), + TokenTransition::Mint(t) => t.base_mut(), + TokenTransition::Transfer(t) => t.base_mut(), + TokenTransition::Freeze(t) => t.base_mut(), + TokenTransition::Unfreeze(t) => t.base_mut(), + TokenTransition::DestroyFrozenFunds(t) => t.base_mut(), + TokenTransition::EmergencyAction(t) => t.base_mut(), + } + } + + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + fn calculate_action_id(&self, owner_id: Identifier) -> Option { + match self { + TokenTransition::Burn(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::Mint(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::Freeze(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::Unfreeze(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::Transfer(_) => None, + TokenTransition::DestroyFrozenFunds(t) => Some(t.calculate_action_id(owner_id)), + TokenTransition::EmergencyAction(t) => Some(t.calculate_action_id(owner_id)), + } + } + + fn can_calculate_action_id(&self) -> bool { + match self { + TokenTransition::Burn(_) + | TokenTransition::Mint(_) + | TokenTransition::Freeze(_) + | TokenTransition::Unfreeze(_) + | TokenTransition::DestroyFrozenFunds(_) + | TokenTransition::EmergencyAction(_) => true, + TokenTransition::Transfer(_) => false, + } + } + + fn set_data_contract_id(&mut self, id: Identifier) { + self.base_mut().set_data_contract_id(id); + } + + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + fn set_token_id(&mut self, token_id: Identifier) { + self.base_mut().set_token_id(token_id) + } + + fn identity_contract_nonce(&self) -> IdentityNonce { + self.base().identity_contract_nonce() + } + + fn set_identity_contract_nonce(&mut self, nonce: IdentityNonce) { + self.base_mut().set_identity_contract_nonce(nonce); + } +} 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 new file mode 100644 index 0000000000..d196637391 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_transition_action_type.rs @@ -0,0 +1,71 @@ +use std::fmt; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::token_transition::TokenTransition; +use crate::ProtocolError; + +// @append-only +#[derive(Eq, PartialEq, Debug, Copy, Clone, Hash)] +pub enum TokenTransitionActionType { + Burn, + Mint, + Transfer, + Freeze, + Unfreeze, + DestroyFrozenFunds, + EmergencyAction, +} + +impl fmt::Display for TokenTransitionActionType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let action_str = match self { + TokenTransitionActionType::Burn => "Burn", + TokenTransitionActionType::Mint => "Mint", + TokenTransitionActionType::Transfer => "Transfer", + TokenTransitionActionType::Freeze => "Freeze", + TokenTransitionActionType::Unfreeze => "Unfreeze", + TokenTransitionActionType::DestroyFrozenFunds => "DestroyFrozenFunds", + TokenTransitionActionType::EmergencyAction => "EmergencyAction", + }; + write!(f, "{}", action_str) + } +} + +pub trait TokenTransitionActionTypeGetter { + fn action_type(&self) -> TokenTransitionActionType; +} + +impl TokenTransitionActionTypeGetter for TokenTransition { + fn action_type(&self) -> TokenTransitionActionType { + match self { + TokenTransition::Burn(_) => TokenTransitionActionType::Burn, + TokenTransition::Mint(_) => TokenTransitionActionType::Mint, + TokenTransition::Transfer(_) => TokenTransitionActionType::Transfer, + TokenTransition::Freeze(_) => TokenTransitionActionType::Freeze, + TokenTransition::Unfreeze(_) => TokenTransitionActionType::Unfreeze, + TokenTransition::DestroyFrozenFunds(_) => TokenTransitionActionType::DestroyFrozenFunds, + TokenTransition::EmergencyAction(_) => TokenTransitionActionType::EmergencyAction, + } + } +} + +impl TryFrom<&str> for TokenTransitionActionType { + type Error = ProtocolError; + + fn try_from(value: &str) -> Result { + match value { + "burn" => Ok(TokenTransitionActionType::Burn), + "issuance" => Ok(TokenTransitionActionType::Mint), + "transfer" => Ok(TokenTransitionActionType::Transfer), + "freeze" => Ok(TokenTransitionActionType::Freeze), + "unfreeze" => Ok(TokenTransitionActionType::Unfreeze), + "destroy_frozen_funds" | "destroyFrozenFunds" => { + Ok(TokenTransitionActionType::DestroyFrozenFunds) + } + "emergency_action" | "emergencyAction" => { + Ok(TokenTransitionActionType::EmergencyAction) + } + action_type => Err(ProtocolError::Generic(format!( + "unknown token transition action type {action_type}" + ))), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/mod.rs new file mode 100644 index 0000000000..4cefde0eff --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/mod.rs @@ -0,0 +1,24 @@ +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::TokenUnfreezeTransitionV0; + +#[derive(Debug, Clone, Encode, Decode, PartialEq, Display, From)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +pub enum TokenUnfreezeTransition { + #[display("V0({})", "_0")] + V0(TokenUnfreezeTransitionV0), +} + +impl Default for TokenUnfreezeTransition { + fn default() -> Self { + TokenUnfreezeTransition::V0(TokenUnfreezeTransitionV0::default()) // since only v0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/mod.rs new file mode 100644 index 0000000000..abdf7892c5 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/mod.rs @@ -0,0 +1,45 @@ +pub mod v0_methods; + +use crate::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use bincode::{Decode, Encode}; +use platform_value::Identifier; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; +use std::fmt; + +mod property_names { + pub const AMOUNT: &str = "$amount"; +} +/// The Identifier fields in [`TokenUnfreezeTransition`] +pub use super::super::document_base_transition::IDENTIFIER_FIELDS; + +#[derive(Debug, Clone, Default, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct TokenUnfreezeTransitionV0 { + /// Document Base Transition + #[cfg_attr(feature = "state-transition-serde-conversion", serde(flatten))] + pub base: TokenBaseTransition, + /// The identity that we are freezing + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "frozenIdentityId") + )] + pub frozen_identity_id: Identifier, + /// The public note + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(rename = "publicNote") + )] + pub public_note: Option, +} + +impl fmt::Display for TokenUnfreezeTransitionV0 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Format the base transition (assuming `TokenBaseTransition` implements Display) + write!(f, "Base: {}, Froze: {}", self.base, self.frozen_identity_id) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/v0_methods.rs new file mode 100644 index 0000000000..d386f30bd6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0/v0_methods.rs @@ -0,0 +1,78 @@ +use platform_value::Identifier; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::batched_transition::token_unfreeze_transition::TokenUnfreezeTransitionV0; +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::TokenUnfreezeTransition; + +impl TokenBaseTransitionAccessors for TokenUnfreezeTransitionV0 { + 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 TokenUnfreezeTransitionV0Methods: + TokenBaseTransitionAccessors + AllowedAsMultiPartyAction +{ + /// Returns the `public_note` field of the `TokenUnfreezeTransitionV0`. + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenUnfreezeTransitionV0`. + fn public_note_owned(self) -> Option; + + /// Sets the value of the `public_note` field in the `TokenUnfreezeTransitionV0`. + fn set_public_note(&mut self, public_note: Option); + + /// Returns the `frozen_identity_id` field of the `TokenUnfreezeTransitionV0`. + fn frozen_identity_id(&self) -> Identifier; + + /// Sets the value of the `frozen_identity_id` field in the `TokenUnfreezeTransitionV0`. + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier); +} + +impl TokenUnfreezeTransitionV0Methods for TokenUnfreezeTransitionV0 { + 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; + } + + fn frozen_identity_id(&self) -> Identifier { + self.frozen_identity_id + } + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + self.frozen_identity_id = frozen_identity_id; + } +} + +impl AllowedAsMultiPartyAction for TokenUnfreezeTransitionV0 { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + let TokenUnfreezeTransitionV0 { + base, + frozen_identity_id, + .. + } = self; + + TokenUnfreezeTransition::calculate_action_id_with_fields( + base.token_id().as_bytes(), + owner_id.as_bytes(), + frozen_identity_id.as_bytes(), + base.identity_contract_nonce(), + ) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0_methods.rs new file mode 100644 index 0000000000..2f660df716 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/batched_transition/token_unfreeze_transition/v0_methods.rs @@ -0,0 +1,85 @@ +use platform_value::Identifier; +use crate::prelude::IdentityNonce; +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_unfreeze_transition::v0::v0_methods::TokenUnfreezeTransitionV0Methods; +use crate::state_transition::batch_transition::TokenUnfreezeTransition; +use crate::util::hash::hash_double; + +impl TokenBaseTransitionAccessors for TokenUnfreezeTransition { + fn base(&self) -> &TokenBaseTransition { + match self { + TokenUnfreezeTransition::V0(v0) => &v0.base, + } + } + + fn base_mut(&mut self) -> &mut TokenBaseTransition { + match self { + TokenUnfreezeTransition::V0(v0) => &mut v0.base, + } + } + + fn set_base(&mut self, base: TokenBaseTransition) { + match self { + TokenUnfreezeTransition::V0(v0) => v0.base = base, + } + } +} + +impl TokenUnfreezeTransitionV0Methods for TokenUnfreezeTransition { + fn public_note(&self) -> Option<&String> { + match self { + TokenUnfreezeTransition::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenUnfreezeTransition::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenUnfreezeTransition::V0(v0) => v0.set_public_note(public_note), + } + } + + fn frozen_identity_id(&self) -> Identifier { + match self { + TokenUnfreezeTransition::V0(v0) => v0.frozen_identity_id(), + } + } + + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + match self { + TokenUnfreezeTransition::V0(v0) => v0.set_frozen_identity_id(frozen_identity_id), + } + } +} + +impl AllowedAsMultiPartyAction for TokenUnfreezeTransition { + fn calculate_action_id(&self, owner_id: Identifier) -> Identifier { + match self { + TokenUnfreezeTransition::V0(v0) => v0.calculate_action_id(owner_id), + } + } +} + +impl TokenUnfreezeTransition { + pub fn calculate_action_id_with_fields( + token_id: &[u8; 32], + owner_id: &[u8; 32], + target_id: &[u8; 32], + identity_contract_nonce: IdentityNonce, + ) -> Identifier { + let mut bytes = b"action_token_unfreeze".to_vec(); + bytes.extend_from_slice(token_id); + bytes.extend_from_slice(owner_id); + bytes.extend_from_slice(target_id); + bytes.extend_from_slice(&identity_contract_nonce.to_be_bytes()); + + hash_double(bytes).into() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/fields.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/fields.rs similarity index 93% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/fields.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/fields.rs index 06f39e42fc..8a72a2d50c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/fields.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/fields.rs @@ -1,7 +1,7 @@ use crate::state_transition::state_transitions; use crate::identity::SecurityLevel; -use crate::state_transition::documents_batch_transition::fields::property_names::{ +use crate::state_transition::batch_transition::fields::property_names::{ OWNER_ID, TRANSITIONS_DATA_CONTRACT_ID, TRANSITIONS_ID, }; pub use state_transitions::common_fields::property_names::{ diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/identity_signed.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/identity_signed.rs new file mode 100644 index 0000000000..a3aba2340b --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/identity_signed.rs @@ -0,0 +1,26 @@ +use crate::identity::{KeyID, Purpose, SecurityLevel}; +use crate::state_transition::batch_transition::BatchTransition; +use crate::state_transition::StateTransitionIdentitySigned; + +impl StateTransitionIdentitySigned for BatchTransition { + fn signature_public_key_id(&self) -> KeyID { + match self { + BatchTransition::V0(transition) => transition.signature_public_key_id(), + BatchTransition::V1(transition) => transition.signature_public_key_id(), + } + } + + fn set_signature_public_key_id(&mut self, key_id: KeyID) { + match self { + BatchTransition::V0(transition) => transition.set_signature_public_key_id(key_id), + BatchTransition::V1(transition) => transition.set_signature_public_key_id(key_id), + } + } + + fn security_level_requirement(&self, purpose: Purpose) -> Vec { + match self { + BatchTransition::V0(transition) => transition.security_level_requirement(purpose), + BatchTransition::V1(transition) => transition.security_level_requirement(purpose), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/json_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/json_conversion.rs similarity index 52% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/json_conversion.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/json_conversion.rs index 1fb61df8b2..80d5c5c791 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/json_conversion.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/json_conversion.rs @@ -1,5 +1,5 @@ -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -use crate::state_transition::state_transitions::documents_batch_transition::fields::*; +use crate::state_transition::batch_transition::BatchTransition; +use crate::state_transition::state_transitions::batch_transition::fields::*; use crate::state_transition::{ JsonStateTransitionSerializationOptions, StateTransitionJsonConvert, }; @@ -7,13 +7,13 @@ use crate::ProtocolError; use serde_json::Number; use serde_json::Value as JsonValue; -impl<'a> StateTransitionJsonConvert<'a> for DocumentsBatchTransition { +impl<'a> StateTransitionJsonConvert<'a> for BatchTransition { fn to_json( &self, options: JsonStateTransitionSerializationOptions, ) -> Result { match self { - DocumentsBatchTransition::V0(transition) => { + BatchTransition::V0(transition) => { let mut value = transition.to_json(options)?; let map_value = value.as_object_mut().expect("expected an object"); map_value.insert( @@ -22,6 +22,15 @@ impl<'a> StateTransitionJsonConvert<'a> for DocumentsBatchTransition { ); Ok(value) } + BatchTransition::V1(transition) => { + let mut value = transition.to_json(options)?; + let map_value = value.as_object_mut().expect("expected an object"); + map_value.insert( + STATE_TRANSITION_PROTOCOL_VERSION.to_string(), + JsonValue::Number(Number::from(1)), + ); + Ok(value) + } } } } 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 new file mode 100644 index 0000000000..f690b7edc2 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/mod.rs @@ -0,0 +1,862 @@ +#[cfg(feature = "state-transition-signing")] +use crate::balances::credits::TokenAmount; +#[cfg(feature = "state-transition-signing")] +use crate::data_contract::document_type::DocumentTypeRef; +#[cfg(feature = "state-transition-signing")] +use crate::data_contract::TokenContractPosition; +#[cfg(feature = "state-transition-signing")] +use crate::document::Document; +use crate::fee::Credits; +#[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; +use crate::prelude::IdentityNonce; +#[cfg(feature = "state-transition-signing")] +use crate::prelude::UserFeeIncrease; +#[cfg(feature = "state-transition-signing")] +use crate::prelude::{ + DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex, +}; +use crate::state_transition::batch_transition::batched_transition::BatchedTransition; +use crate::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use crate::state_transition::batch_transition::methods::v1::DocumentsBatchTransitionMethodsV1; +use crate::state_transition::batch_transition::BatchTransition; +#[cfg(feature = "state-transition-signing")] +use crate::state_transition::batch_transition::{BatchTransitionV0, BatchTransitionV1}; +#[cfg(feature = "state-transition-signing")] +use crate::state_transition::StateTransition; +use crate::tokens::emergency_action::TokenEmergencyAction; +use crate::ProtocolError; +#[cfg(feature = "state-transition-signing")] +use platform_value::Identifier; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::{FeatureVersion, PlatformVersion}; + +pub mod v0; +pub mod v1; + +impl DocumentsBatchTransitionMethodsV0 for BatchTransition { + fn all_document_purchases_amount(&self) -> Result, ProtocolError> { + match self { + BatchTransition::V0(v0) => v0.all_document_purchases_amount(), + BatchTransition::V1(v1) => v1.all_document_purchases_amount(), + } + } + + fn all_conflicting_index_collateral_voting_funds( + &self, + ) -> Result, ProtocolError> { + match self { + BatchTransition::V0(v0) => v0.all_conflicting_index_collateral_voting_funds(), + BatchTransition::V1(v1) => v1.all_conflicting_index_collateral_voting_funds(), + } + } + + fn set_transitions(&mut self, transitions: Vec) { + match self { + BatchTransition::V0(v0) => v0.set_transitions(transitions), + BatchTransition::V1(v1) => v1.set_transitions(transitions), + } + } + + fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { + match self { + BatchTransition::V0(v0) => v0.set_identity_contract_nonce(identity_contract_nonce), + BatchTransition::V1(v1) => v1.set_identity_contract_nonce(identity_contract_nonce), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_creation_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + entropy: [u8; 32], + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + create_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 0 => Ok( + BatchTransitionV0::new_document_creation_transition_from_document( + document, + document_type, + entropy, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + create_feature_version, + base_feature_version, + )?, + ), + 1 => Ok( + BatchTransitionV1::new_document_creation_transition_from_document( + document, + document_type, + entropy, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + create_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_created_from_document".to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_replacement_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + replace_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 0 => Ok( + BatchTransitionV0::new_document_replacement_transition_from_document( + document, + document_type, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + replace_feature_version, + base_feature_version, + )?, + ), + 1 => Ok( + BatchTransitionV1::new_document_replacement_transition_from_document( + document, + document_type, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + replace_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: + "DocumentsBatchTransition::new_document_replacement_transition_from_document" + .to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_transfer_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + recipient_owner_id: Identifier, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + transfer_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 0 => Ok( + BatchTransitionV0::new_document_transfer_transition_from_document( + document, + document_type, + recipient_owner_id, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + transfer_feature_version, + base_feature_version, + )?, + ), + 1 => Ok( + BatchTransitionV1::new_document_transfer_transition_from_document( + document, + document_type, + recipient_owner_id, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + transfer_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: + "DocumentsBatchTransition::new_document_replacement_transition_from_document" + .to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_deletion_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 0 => Ok( + BatchTransitionV0::new_document_deletion_transition_from_document( + document, + document_type, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + )?, + ), + 1 => Ok( + BatchTransitionV1::new_document_deletion_transition_from_document( + document, + document_type, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_document_deletion_transition_from_document" + .to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_update_price_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + update_price_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 0 => Ok( + BatchTransitionV0::new_document_update_price_transition_from_document( + document, + document_type, + price, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + update_price_feature_version, + base_feature_version, + )?, + ), + 1 => Ok( + BatchTransitionV1::new_document_update_price_transition_from_document( + document, + document_type, + price, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + update_price_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: + "DocumentsBatchTransition::new_document_update_price_transition_from_document" + .to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_purchase_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + new_owner_id: Identifier, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + purchase_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 0 => Ok( + BatchTransitionV0::new_document_purchase_transition_from_document( + document, + document_type, + new_owner_id, + price, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + purchase_feature_version, + base_feature_version, + )?, + ), + 1 => Ok( + BatchTransitionV1::new_document_purchase_transition_from_document( + document, + document_type, + new_owner_id, + price, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + purchase_feature_version, + base_feature_version, + )?, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_document_purchase_transition_from_document" + .to_string(), + known_versions: vec![0, 1], + received: version, + }), + } + } +} + +impl DocumentsBatchTransitionMethodsV1 for BatchTransition { + #[cfg(feature = "state-transition-signing")] + fn new_token_mint_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: TokenContractPosition, + amount: TokenAmount, + issued_to_identity_id: Option, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + BatchTransitionV1::new_token_mint_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + amount, + issued_to_identity_id, + public_note, + using_group_info, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_mint_transition".to_string(), + known_versions: vec![1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_burn_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + BatchTransitionV1::new_token_burn_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + amount, + public_note, + using_group_info, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_burn_transition".to_string(), + known_versions: vec![1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_transfer_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + recipient_id: Identifier, + public_note: Option, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + // Create the transfer transition for batch version 1 + BatchTransitionV1::new_token_transfer_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + amount, + recipient_id, + public_note, + shared_encrypted_note, + private_encrypted_note, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_transfer_transition".to_string(), + known_versions: vec![1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_freeze_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + freeze_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + // Create the freeze transition for batch version 1 + BatchTransitionV1::new_token_freeze_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + freeze_identity_id, + public_note, + using_group_info, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_freeze_transition".to_string(), + known_versions: vec![1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_unfreeze_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + unfreeze_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + // Create the freeze transition for batch version 1 + BatchTransitionV1::new_token_unfreeze_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + unfreeze_identity_id, + public_note, + using_group_info, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_unfreeze_transition".to_string(), + known_versions: vec![1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_destroy_frozen_funds_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + // Create the destroy frozen funds transition for batch version 1 + BatchTransitionV1::new_token_destroy_frozen_funds_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + frozen_identity_id, + public_note, + using_group_info, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_destroy_frozen_funds_transition" + .to_string(), + known_versions: vec![1], + received: version, + }), + } + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_emergency_action_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + emergency_action: TokenEmergencyAction, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + match batch_feature_version.unwrap_or( + platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .default_current_version, + ) { + 1 | 0 + if platform_version + .dpp + .state_transition_serialization_versions + .batch_state_transition + .max_version + >= 1 => + { + // Create the emergency action transition for batch version 1 + BatchTransitionV1::new_token_emergency_action_transition( + token_id, + owner_id, + data_contract_id, + token_contract_position, + emergency_action, + public_note, + using_group_info, + identity_public_key, + identity_contract_nonce, + user_fee_increase, + signer, + platform_version, + batch_feature_version, + delete_feature_version, + base_feature_version, + ) + } + version => Err(ProtocolError::UnknownVersionMismatch { + method: "DocumentsBatchTransition::new_token_emergency_action_transition" + .to_string(), + known_versions: vec![1], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs similarity index 81% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs index ceffcaa7ae..eaadd2777a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v0/mod.rs @@ -11,11 +11,8 @@ use crate::identity::SecurityLevel; use crate::prelude::IdentityNonce; #[cfg(feature = "state-transition-signing")] use crate::prelude::UserFeeIncrease; -use crate::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentTransition, DocumentTransitionV0Methods, -}; +use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; #[cfg(feature = "state-transition-signing")] use crate::state_transition::StateTransition; use crate::ProtocolError; @@ -23,6 +20,8 @@ use platform_value::Identifier; #[cfg(feature = "state-transition-signing")] use platform_version::version::{FeatureVersion, PlatformVersion}; use std::convert::TryFrom; +use crate::state_transition::batch_transition::batched_transition::{BatchedTransition, BatchedTransitionRef}; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 { #[cfg(feature = "state-transition-signing")] @@ -129,17 +128,19 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 // requirement is the highest level across all documents affected by the ST./ let mut highest_security_level = SecurityLevel::lowest_level(); - for transition in self.transitions().iter() { - let document_type_name = transition.base().document_type_name(); - let data_contract_id = transition.base().data_contract_id(); - let document_security_level = get_data_contract_security_level_requirement( - data_contract_id, - document_type_name.to_owned(), - )?; + for transition in self.transitions_iter() { + if let BatchedTransitionRef::Document(document_transition) = transition { + let document_type_name = document_transition.base().document_type_name(); + let data_contract_id = document_transition.base().data_contract_id(); + let document_security_level = get_data_contract_security_level_requirement( + data_contract_id, + document_type_name.to_owned(), + )?; - // lower enum enum representation means higher in security - if document_security_level < highest_security_level { - highest_security_level = document_security_level + // lower enum representation means higher in security + if document_security_level < highest_security_level { + highest_security_level = document_security_level + } } } Ok(if highest_security_level == SecurityLevel::MASTER { @@ -152,7 +153,7 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 }) } - fn set_transitions(&mut self, transitions: Vec); + fn set_transitions(&mut self, transitions: Vec); fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce); @@ -160,5 +161,5 @@ pub trait DocumentsBatchTransitionMethodsV0: DocumentsBatchTransitionAccessorsV0 &self, ) -> Result, ProtocolError>; - fn all_purchases_amount(&self) -> Result, ProtocolError>; + fn all_document_purchases_amount(&self) -> Result, ProtocolError>; } 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 new file mode 100644 index 0000000000..db4e2efab7 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/methods/v1/mod.rs @@ -0,0 +1,157 @@ +use crate::balances::credits::TokenAmount; +use crate::group::GroupStateTransitionInfoStatus; +use crate::identity::signer::Signer; +use crate::identity::IdentityPublicKey; +use crate::prelude::{ + DerivationEncryptionKeyIndex, IdentityNonce, RecipientKeyIndex, RootEncryptionKeyIndex, + SenderKeyIndex, UserFeeIncrease, +}; +use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::StateTransition; +use crate::tokens::emergency_action::TokenEmergencyAction; +use crate::version::FeatureVersion; +use crate::ProtocolError; +use platform_value::Identifier; +use platform_version::version::PlatformVersion; + +pub trait DocumentsBatchTransitionMethodsV1: DocumentsBatchTransitionAccessorsV0 { + #[cfg(feature = "state-transition-signing")] + fn new_token_mint_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + issued_to_identity_id: Option, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_token_burn_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_token_transfer_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + recipient_id: Identifier, + public_note: Option, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_token_freeze_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_token_unfreeze_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_token_destroy_frozen_funds_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; + + #[cfg(feature = "state-transition-signing")] + fn new_token_emergency_action_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + emergency_action: TokenEmergencyAction, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result; +} 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 new file mode 100644 index 0000000000..a3600a133c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/mod.rs @@ -0,0 +1,115 @@ +use bincode::{Decode, Encode}; + +use std::convert::TryInto; + +use derive_more::From; + +use platform_value::Value; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +use crate::ProtocolError; +use crate::{identity::SecurityLevel, state_transition::StateTransitionFieldTypes}; + +pub use self::batched_transition::{ + document_base_transition, document_create_transition, + document_create_transition::DocumentCreateTransition, document_delete_transition, + document_delete_transition::DocumentDeleteTransition, document_replace_transition, + document_replace_transition::DocumentReplaceTransition, token_base_transition, + token_burn_transition, token_burn_transition::TokenBurnTransition, + token_destroy_frozen_funds_transition, + token_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransition, + token_emergency_action_transition, + token_emergency_action_transition::TokenEmergencyActionTransition, token_freeze_transition, + token_freeze_transition::TokenFreezeTransition, token_mint_transition, + token_mint_transition::TokenMintTransition, token_transfer_transition, + token_transfer_transition::TokenTransferTransition, token_unfreeze_transition, + token_unfreeze_transition::TokenUnfreezeTransition, +}; + +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_versioning::PlatformVersioned; + +pub mod accessors; +pub mod batched_transition; +pub mod fields; +mod identity_signed; +#[cfg(feature = "state-transition-json-conversion")] +mod json_conversion; +pub mod methods; +pub mod resolvers; +mod state_transition_like; +mod v0; +mod v1; +#[cfg(feature = "validation")] +mod validation; +#[cfg(feature = "state-transition-value-conversion")] +mod value_conversion; +mod version; + +use crate::state_transition::data_contract_update_transition::{ + SIGNATURE, SIGNATURE_PUBLIC_KEY_ID, +}; + +use crate::state_transition::batch_transition::fields::property_names; + +use crate::identity::state_transition::OptionallyAssetLockProved; +pub use v0::*; +pub use v1::*; + +#[derive( + Debug, + Clone, + PartialEq, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformSignable, + PlatformVersioned, + From, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(tag = "$version") +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +#[platform_version_path_bounds( + "dpp.state_transition_serialization_versions.batch_state_transition" +)] +pub enum BatchTransition { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] + V0(BatchTransitionV0), + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "1"))] + V1(BatchTransitionV1), +} + +impl StateTransitionFieldTypes for BatchTransition { + fn binary_property_paths() -> Vec<&'static str> { + vec![SIGNATURE] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![property_names::OWNER_ID] + } + + fn signature_property_paths() -> Vec<&'static str> { + vec![SIGNATURE, SIGNATURE_PUBLIC_KEY_ID] + } +} + +// TODO: Make a DocumentType method +pub fn get_security_level_requirement(v: &Value, default: SecurityLevel) -> SecurityLevel { + let maybe_security_level: Option = v + .get_optional_integer(property_names::SECURITY_LEVEL_REQUIREMENT) + // TODO: Data Contract must already valid so there is no chance that this will fail + .expect("document schema must be a map"); + + match maybe_security_level { + Some(some_level) => (some_level as u8).try_into().unwrap_or(default), + None => default, + } +} + +impl OptionallyAssetLockProved for BatchTransition {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/mod.rs new file mode 100644 index 0000000000..2d24cd45f5 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/mod.rs @@ -0,0 +1 @@ +pub mod v0; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs new file mode 100644 index 0000000000..8dd6fd6ec1 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/resolvers/v0/mod.rs @@ -0,0 +1,26 @@ +use crate::state_transition::batch_transition::batched_transition::token_unfreeze_transition::TokenUnfreezeTransition; +use crate::state_transition::batch_transition::batched_transition::{ + DocumentPurchaseTransition, DocumentTransferTransition, +}; +use crate::state_transition::batch_transition::{ + DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, + TokenBurnTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, + TokenFreezeTransition, TokenMintTransition, TokenTransferTransition, +}; + +pub trait BatchTransitionResolversV0 { + fn as_transition_create(&self) -> Option<&DocumentCreateTransition>; + fn as_transition_replace(&self) -> Option<&DocumentReplaceTransition>; + fn as_transition_delete(&self) -> Option<&DocumentDeleteTransition>; + fn as_transition_transfer(&self) -> Option<&DocumentTransferTransition>; + fn as_transition_purchase(&self) -> Option<&DocumentPurchaseTransition>; + fn as_transition_token_burn(&self) -> Option<&TokenBurnTransition>; + fn as_transition_token_mint(&self) -> Option<&TokenMintTransition>; + fn as_transition_token_transfer(&self) -> Option<&TokenTransferTransition>; + fn as_transition_token_freeze(&self) -> Option<&TokenFreezeTransition>; + fn as_transition_token_unfreeze(&self) -> Option<&TokenUnfreezeTransition>; + fn as_transition_token_destroy_frozen_funds( + &self, + ) -> Option<&TokenDestroyFrozenFundsTransition>; + fn as_transition_token_emergency_action(&self) -> Option<&TokenEmergencyActionTransition>; +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/state_transition_like.rs new file mode 100644 index 0000000000..0221ced261 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/state_transition_like.rs @@ -0,0 +1,79 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::batch_transition::BatchTransition; +use crate::state_transition::{StateTransitionLike, StateTransitionType}; +use crate::version::FeatureVersion; +use platform_value::{BinaryData, Identifier}; + +impl StateTransitionLike for BatchTransition { + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + match self { + BatchTransition::V0(transition) => transition.modified_data_ids(), + BatchTransition::V1(transition) => transition.modified_data_ids(), + } + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + match self { + BatchTransition::V0(_) => 0, + BatchTransition::V1(_) => 1, + } + } + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + match self { + BatchTransition::V0(transition) => transition.state_transition_type(), + BatchTransition::V1(transition) => transition.state_transition_type(), + } + } + /// returns the signature as a byte-array + fn signature(&self) -> &BinaryData { + match self { + BatchTransition::V0(transition) => transition.signature(), + BatchTransition::V1(transition) => transition.signature(), + } + } + /// set a new signature + fn set_signature(&mut self, signature: BinaryData) { + match self { + BatchTransition::V0(transition) => transition.set_signature(signature), + BatchTransition::V1(transition) => transition.set_signature(signature), + } + } + + fn set_signature_bytes(&mut self, signature: Vec) { + match self { + BatchTransition::V0(transition) => transition.set_signature_bytes(signature), + BatchTransition::V1(transition) => transition.set_signature_bytes(signature), + } + } + + /// returns the fee multiplier + fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + BatchTransition::V0(transition) => transition.user_fee_increase(), + BatchTransition::V1(transition) => transition.user_fee_increase(), + } + } + /// set a fee multiplier + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + match self { + BatchTransition::V0(transition) => transition.set_user_fee_increase(user_fee_increase), + BatchTransition::V1(transition) => transition.set_user_fee_increase(user_fee_increase), + } + } + + fn owner_id(&self) -> Identifier { + match self { + BatchTransition::V0(transition) => transition.owner_id(), + BatchTransition::V1(transition) => transition.owner_id(), + } + } + + fn unique_identifiers(&self) -> Vec { + match self { + BatchTransition::V0(transition) => transition.unique_identifiers(), + BatchTransition::V1(transition) => transition.unique_identifiers(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/cbor_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/cbor_conversion.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/cbor_conversion.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/cbor_conversion.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/identity_signed.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/identity_signed.rs similarity index 83% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/identity_signed.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/identity_signed.rs index bdc0fe583a..d0f7084b33 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/identity_signed.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/identity_signed.rs @@ -1,10 +1,10 @@ use crate::identity::SecurityLevel::{CRITICAL, HIGH, MEDIUM}; use crate::identity::{KeyID, Purpose, SecurityLevel}; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; +use crate::state_transition::batch_transition::BatchTransitionV0; use crate::state_transition::StateTransitionIdentitySigned; -impl StateTransitionIdentitySigned for DocumentsBatchTransitionV0 { +impl StateTransitionIdentitySigned for BatchTransitionV0 { fn signature_public_key_id(&self) -> KeyID { self.signature_public_key_id } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/json_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/json_conversion.rs new file mode 100644 index 0000000000..59ec75a2e6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/json_conversion.rs @@ -0,0 +1,4 @@ +use crate::state_transition::batch_transition::BatchTransitionV0; +use crate::state_transition::StateTransitionJsonConvert; + +impl<'a> StateTransitionJsonConvert<'a> for BatchTransitionV0 {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/mod.rs similarity index 86% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/mod.rs index 4f301bb452..3bd2cb1d1a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/mod.rs @@ -10,7 +10,7 @@ mod version; use crate::identity::KeyID; -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; use crate::ProtocolError; use bincode::{Decode, Encode}; use platform_serialization_derive::PlatformSignable; @@ -26,7 +26,7 @@ use serde::{Deserialize, Serialize}; derive(Serialize, Deserialize) )] #[derive(Default)] -pub struct DocumentsBatchTransitionV0 { +pub struct BatchTransitionV0 { pub owner_id: Identifier, pub transitions: Vec, pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/state_transition_like.rs similarity index 72% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/state_transition_like.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/state_transition_like.rs index ce3faf2c4b..83eb9f4244 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/state_transition_like.rs @@ -1,24 +1,24 @@ use crate::prelude::UserFeeIncrease; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransitionV0Methods; -use crate::state_transition::documents_batch_transition::{ - DocumentsBatchTransition, DocumentsBatchTransitionV0, +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; +use crate::state_transition::batch_transition::{ + BatchTransition, BatchTransitionV0, }; -use crate::state_transition::StateTransitionType::DocumentsBatch; +use crate::state_transition::StateTransitionType::Batch; use crate::state_transition::{StateTransition, StateTransitionLike, StateTransitionType}; use crate::version::FeatureVersion; use base64::prelude::BASE64_STANDARD; use base64::Engine; use platform_value::{BinaryData, Identifier}; -impl From for StateTransition { - fn from(value: DocumentsBatchTransitionV0) -> Self { - let document_batch_transition: DocumentsBatchTransition = value.into(); +impl From for StateTransition { + fn from(value: BatchTransitionV0) -> Self { + let document_batch_transition: BatchTransition = value.into(); document_batch_transition.into() } } -impl StateTransitionLike for DocumentsBatchTransitionV0 { +impl StateTransitionLike for BatchTransitionV0 { /// Returns ID of the created contract fn modified_data_ids(&self) -> Vec { self.transitions.iter().map(|t| t.base().id()).collect() @@ -29,7 +29,7 @@ impl StateTransitionLike for DocumentsBatchTransitionV0 { } /// returns the type of State Transition fn state_transition_type(&self) -> StateTransitionType { - DocumentsBatch + Batch } /// returns the signature as a byte-array fn signature(&self) -> &BinaryData { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/types.rs similarity index 53% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/types.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/types.rs index 39d85d6437..abe0ef311e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/types.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/types.rs @@ -1,9 +1,9 @@ -use crate::state_transition::documents_batch_transition::fields::property_names::*; -use crate::state_transition::documents_batch_transition::fields::*; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; +use crate::state_transition::batch_transition::fields::property_names::*; +use crate::state_transition::batch_transition::fields::*; +use crate::state_transition::batch_transition::BatchTransitionV0; use crate::state_transition::StateTransitionFieldTypes; -impl StateTransitionFieldTypes for DocumentsBatchTransitionV0 { +impl StateTransitionFieldTypes for BatchTransitionV0 { fn binary_property_paths() -> Vec<&'static str> { vec![SIGNATURE] } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs similarity index 77% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs index 0bafe6b8ae..17b7c8df12 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/v0_methods.rs @@ -1,3 +1,4 @@ +use std::slice::Iter; #[cfg(feature = "state-transition-signing")] use crate::data_contract::document_type::DocumentTypeRef; #[cfg(feature = "state-transition-signing")] @@ -12,21 +13,19 @@ use crate::prelude::IdentityNonce; use crate::prelude::IdentityPublicKey; #[cfg(feature = "state-transition-signing")] use crate::prelude::UserFeeIncrease; -use crate::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::batch_transition::accessors::{DocumentsBatchTransitionAccessorsV0}; #[cfg(feature = "state-transition-signing")] -use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; -use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentTransition, DocumentTransitionV0Methods, -}; +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::batched_transition::{BatchedTransition, BatchedTransitionMutRef, BatchedTransitionRef}; #[cfg(feature = "state-transition-signing")] -use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentReplaceTransition, DocumentTransferTransition, DocumentPurchaseTransition, DocumentUpdatePriceTransition, +use crate::state_transition::batch_transition::batched_transition::{ + DocumentPurchaseTransition, DocumentReplaceTransition, DocumentTransferTransition, DocumentUpdatePriceTransition, }; -use crate::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; +use crate::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use crate::state_transition::batch_transition::BatchTransitionV0; #[cfg(feature = "state-transition-signing")] -use crate::state_transition::documents_batch_transition::{ - DocumentDeleteTransition, DocumentsBatchTransition, +use crate::state_transition::batch_transition::{ + BatchTransition, DocumentDeleteTransition, }; #[cfg(feature = "state-transition-signing")] use crate::state_transition::StateTransition; @@ -35,20 +34,49 @@ use crate::ProtocolError; use platform_value::Identifier; #[cfg(feature = "state-transition-signing")] use platform_version::version::{FeatureVersion, PlatformVersion}; -use crate::state_transition::documents_batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::document_transition::DocumentTransition; +use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; + +impl DocumentsBatchTransitionAccessorsV0 for BatchTransitionV0 { + type IterType<'a> + = std::iter::Map< + Iter<'a, DocumentTransition>, + fn(&'a DocumentTransition) -> BatchedTransitionRef<'a>, + > + where + Self: 'a; + + /// Iterator for `BatchedTransitionRef` items in version 0. + fn transitions_iter<'a>(&'a self) -> Self::IterType<'a> { + self.transitions.iter().map(BatchedTransitionRef::Document) + } + + /// Returns the total number of transitions (document and token) in version 0. + fn transitions_len(&self) -> usize { + self.transitions.len() + } -impl DocumentsBatchTransitionAccessorsV0 for DocumentsBatchTransitionV0 { - fn transitions(&self) -> &Vec { - &self.transitions + /// Checks if there are no transitions in version 0. + fn transitions_are_empty(&self) -> bool { + self.transitions.is_empty() } - fn transitions_slice(&self) -> &[DocumentTransition] { - self.transitions.as_slice() + /// Returns the first transition, if it exists, as a `BatchedTransitionRef`. + fn first_transition(&self) -> Option { + self.transitions.first().map(BatchedTransitionRef::Document) + } + + fn first_transition_mut(&mut self) -> Option { + self.transitions + .first_mut() + .map(BatchedTransitionMutRef::Document) } } -impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { +impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV0 { #[cfg(feature = "state-transition-signing")] fn new_document_creation_transition_from_document( document: Document, @@ -73,7 +101,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { create_feature_version, base_feature_version, )?; - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV0 { owner_id, transitions: vec![create_transition.into()], user_fee_increase, @@ -112,7 +140,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { replace_feature_version, base_feature_version, )?; - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV0 { owner_id, transitions: vec![replace_transition.into()], user_fee_increase, @@ -153,7 +181,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { transfer_feature_version, base_feature_version, )?; - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV0 { owner_id, transitions: vec![transfer_transition.into()], user_fee_increase, @@ -192,7 +220,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { delete_feature_version, base_feature_version, )?; - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV0 { owner_id, transitions: vec![delete_transition.into()], user_fee_increase, @@ -233,7 +261,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { update_price_feature_version, base_feature_version, )?; - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV0 { owner_id, transitions: vec![transfer_transition.into()], user_fee_increase, @@ -274,7 +302,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { purchase_feature_version, base_feature_version, )?; - let documents_batch_transition: DocumentsBatchTransition = DocumentsBatchTransitionV0 { + let documents_batch_transition: BatchTransition = BatchTransitionV0 { owner_id: new_owner_id, transitions: vec![purchase_transition.into()], user_fee_increase, @@ -291,8 +319,14 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { Ok(state_transition) } - fn set_transitions(&mut self, transitions: Vec) { - self.transitions = transitions; + fn set_transitions(&mut self, transitions: Vec) { + self.transitions = transitions + .into_iter() + .filter_map(|batched_transition| match batched_transition { + BatchedTransition::Document(document) => Some(document), + BatchedTransition::Token(_) => None, + }) + .collect(); } fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { @@ -301,7 +335,7 @@ impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransitionV0 { .for_each(|transition| transition.set_identity_contract_nonce(identity_contract_nonce)); } - fn all_purchases_amount(&self) -> Result, ProtocolError> { + fn all_document_purchases_amount(&self) -> Result, ProtocolError> { let (total, any_purchases): (Option, bool) = self .transitions .iter() diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/value_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/value_conversion.rs new file mode 100644 index 0000000000..5438c1e2d0 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/value_conversion.rs @@ -0,0 +1,4 @@ +use crate::state_transition::batch_transition::BatchTransitionV0; +use crate::state_transition::StateTransitionValueConvert; + +impl<'a> StateTransitionValueConvert<'a> for BatchTransitionV0 {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/version.rs similarity index 52% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/version.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/version.rs index e087f12cb9..c8a27eafe8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/version.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v0/version.rs @@ -1,8 +1,8 @@ -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; +use crate::state_transition::batch_transition::BatchTransitionV0; use crate::state_transition::FeatureVersioned; use crate::version::FeatureVersion; -impl FeatureVersioned for DocumentsBatchTransitionV0 { +impl FeatureVersioned for BatchTransitionV0 { fn feature_version(&self) -> FeatureVersion { 0 } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/identity_signed.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/identity_signed.rs new file mode 100644 index 0000000000..cb735d5d76 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/identity_signed.rs @@ -0,0 +1,23 @@ +use crate::identity::SecurityLevel::{CRITICAL, HIGH, MEDIUM}; +use crate::identity::{KeyID, Purpose, SecurityLevel}; + +use crate::state_transition::batch_transition::BatchTransitionV1; +use crate::state_transition::StateTransitionIdentitySigned; + +impl StateTransitionIdentitySigned for BatchTransitionV1 { + fn signature_public_key_id(&self) -> KeyID { + self.signature_public_key_id + } + + fn set_signature_public_key_id(&mut self, key_id: KeyID) { + self.signature_public_key_id = key_id + } + + fn security_level_requirement(&self, _purpose: Purpose) -> Vec { + // These are the available key levels that must sign the state transition + // However the fact that it is signed by one of these does not guarantee that it + // meets the security level requirement, as that is dictated from within the data + // contract + vec![CRITICAL, HIGH, MEDIUM] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/json_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/json_conversion.rs new file mode 100644 index 0000000000..b277e90e87 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/json_conversion.rs @@ -0,0 +1,4 @@ +use crate::state_transition::batch_transition::BatchTransitionV1; +use crate::state_transition::StateTransitionJsonConvert; + +impl<'a> StateTransitionJsonConvert<'a> for BatchTransitionV1 {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/mod.rs new file mode 100644 index 0000000000..763f93b49a --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/mod.rs @@ -0,0 +1,37 @@ +mod identity_signed; +#[cfg(feature = "state-transition-json-conversion")] +mod json_conversion; +mod state_transition_like; +mod types; +mod v0_methods; +#[cfg(feature = "state-transition-value-conversion")] +mod value_conversion; +mod version; + +use crate::identity::KeyID; + +use crate::state_transition::batch_transition::batched_transition::BatchedTransition; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::PlatformSignable; + +use crate::prelude::UserFeeIncrease; +use platform_value::{BinaryData, Identifier}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Encode, Decode, PlatformSignable)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize) +)] +#[derive(Default)] +pub struct BatchTransitionV1 { + pub owner_id: Identifier, + pub transitions: Vec, + pub user_fee_increase: UserFeeIncrease, + #[platform_signable(exclude_from_sig_hash)] + pub signature_public_key_id: KeyID, + #[platform_signable(exclude_from_sig_hash)] + pub signature: BinaryData, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/state_transition_like.rs new file mode 100644 index 0000000000..f215e8156b --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/state_transition_like.rs @@ -0,0 +1,92 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; +use crate::state_transition::batch_transition::{BatchTransition, BatchTransitionV1}; +use crate::state_transition::StateTransitionType::Batch; +use crate::state_transition::{StateTransition, StateTransitionLike, StateTransitionType}; +use crate::version::FeatureVersion; +use base64::prelude::BASE64_STANDARD; +use base64::Engine; +use platform_value::{BinaryData, Identifier}; +use crate::state_transition::batch_transition::batched_transition::BatchedTransition; +use crate::state_transition::batch_transition::batched_transition::token_transition::TokenTransitionV0Methods; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; + +impl From for StateTransition { + fn from(value: BatchTransitionV1) -> Self { + let document_batch_transition: BatchTransition = value.into(); + document_batch_transition.into() + } +} + +impl StateTransitionLike for BatchTransitionV1 { + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + self.transitions + .iter() + .filter_map(|t| match t { + BatchedTransition::Document(document_transition) => { + Some(document_transition.base().id()) + } + BatchedTransition::Token(_) => None, + }) + .collect() + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + 1 + } + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + Batch + } + /// returns the signature as a byte-array + fn signature(&self) -> &BinaryData { + &self.signature + } + /// set a new signature + fn set_signature(&mut self, signature: BinaryData) { + self.signature = signature + } + + fn set_signature_bytes(&mut self, signature: Vec) { + self.signature = BinaryData::new(signature) + } + + /// Get owner ID + fn owner_id(&self) -> Identifier { + self.owner_id + } + + /// We create a list of unique identifiers for the batch + fn unique_identifiers(&self) -> Vec { + self.transitions + .iter() + .map(|transition| match transition { + BatchedTransition::Document(document_transition) => { + format!( + "{}-{}-{:x}", + BASE64_STANDARD.encode(self.owner_id), + BASE64_STANDARD.encode(document_transition.data_contract_id()), + document_transition.identity_contract_nonce() + ) + } + BatchedTransition::Token(token_transition) => { + format!( + "{}-{}-{:x}", + BASE64_STANDARD.encode(self.owner_id), + BASE64_STANDARD.encode(token_transition.data_contract_id()), + token_transition.identity_contract_nonce() + ) + } + }) + .collect() + } + + fn user_fee_increase(&self) -> UserFeeIncrease { + self.user_fee_increase + } + + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + self.user_fee_increase = user_fee_increase + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/types.rs new file mode 100644 index 0000000000..2a3095b8f9 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/types.rs @@ -0,0 +1,18 @@ +use crate::state_transition::batch_transition::fields::property_names::*; +use crate::state_transition::batch_transition::fields::*; +use crate::state_transition::batch_transition::BatchTransitionV1; +use crate::state_transition::StateTransitionFieldTypes; + +impl StateTransitionFieldTypes for BatchTransitionV1 { + fn binary_property_paths() -> Vec<&'static str> { + vec![SIGNATURE] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![OWNER_ID] + } + + fn signature_property_paths() -> Vec<&'static str> { + vec![SIGNATURE, SIGNATURE_PUBLIC_KEY_ID] + } +} 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 new file mode 100644 index 0000000000..91d9120c44 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/v0_methods.rs @@ -0,0 +1,894 @@ +#[cfg(feature = "state-transition-signing")] +use crate::data_contract::document_type::DocumentTypeRef; +#[cfg(feature = "state-transition-signing")] +use crate::document::{Document, DocumentV0Getters}; +use crate::fee::Credits; +#[cfg(feature = "state-transition-signing")] +use crate::identity::signer::Signer; +#[cfg(feature = "state-transition-signing")] +use crate::identity::SecurityLevel; +#[cfg(feature = "state-transition-signing")] +use crate::prelude::IdentityPublicKey; +#[cfg(feature = "state-transition-signing")] +use crate::prelude::UserFeeIncrease; +use crate::prelude::{ + DerivationEncryptionKeyIndex, IdentityNonce, RecipientKeyIndex, RootEncryptionKeyIndex, + SenderKeyIndex, +}; +use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::batch_transition::batched_transition::{ + BatchedTransition, BatchedTransitionMutRef, BatchedTransitionRef, +}; +#[cfg(feature = "state-transition-signing")] +use crate::state_transition::batch_transition::batched_transition::{ + DocumentPurchaseTransition, DocumentReplaceTransition, DocumentTransferTransition, + DocumentUpdatePriceTransition, +}; +#[cfg(feature = "state-transition-signing")] +use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; +use crate::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use std::iter::Map; +use std::slice::Iter; + +use crate::state_transition::batch_transition::{BatchTransitionV1, TokenBurnTransition, TokenDestroyFrozenFundsTransition, TokenEmergencyActionTransition, TokenFreezeTransition, TokenMintTransition, TokenTransferTransition, TokenUnfreezeTransition}; +#[cfg(feature = "state-transition-signing")] +use crate::state_transition::batch_transition::{ + BatchTransition, DocumentDeleteTransition, +}; +#[cfg(feature = "state-transition-signing")] +use crate::state_transition::StateTransition; +use crate::ProtocolError; +#[cfg(feature = "state-transition-signing")] +use platform_value::Identifier; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::{FeatureVersion, PlatformVersion}; +use crate::balances::credits::TokenAmount; +use crate::group::{GroupStateTransitionInfo, GroupStateTransitionInfoStatus}; +use crate::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use crate::state_transition::batch_transition::batched_transition::multi_party_action::AllowedAsMultiPartyAction; +use crate::state_transition::batch_transition::methods::v1::DocumentsBatchTransitionMethodsV1; +use crate::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; +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::TokenBaseTransitionV0; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_burn_transition::TokenBurnTransitionV0; +use crate::state_transition::batch_transition::token_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransitionV0; +use crate::state_transition::batch_transition::token_emergency_action_transition::TokenEmergencyActionTransitionV0; +use crate::state_transition::batch_transition::token_freeze_transition::TokenFreezeTransitionV0; +use crate::state_transition::batch_transition::token_mint_transition::TokenMintTransitionV0; +use crate::state_transition::batch_transition::token_transfer_transition::TokenTransferTransitionV0; +use crate::state_transition::batch_transition::token_unfreeze_transition::TokenUnfreezeTransitionV0; +#[cfg(feature = "state-transition-signing")] +use crate::tokens::emergency_action::TokenEmergencyAction; + +impl DocumentsBatchTransitionAccessorsV0 for BatchTransitionV1 { + type IterType<'a> + = Map, fn(&'a BatchedTransition) -> BatchedTransitionRef<'a>> + where + Self: 'a; + + /// Iterator for `BatchedTransitionRef` items in version 1. + fn transitions_iter<'a>(&'a self) -> Self::IterType<'a> { + self.transitions + .iter() + .map(|transition| transition.borrow_as_ref()) + } + + /// Returns the total number of transitions (document and token) in version 1. + fn transitions_len(&self) -> usize { + self.transitions.len() + } + + /// Checks if there are no transitions in version 1. + fn transitions_are_empty(&self) -> bool { + self.transitions.is_empty() + } + + /// Returns the first transition, if it exists, as a `BatchedTransitionRef`. + fn first_transition(&self) -> Option { + self.transitions + .first() + .map(|transition| transition.borrow_as_ref()) + } + + /// Returns the first transition, if it exists, as a `BatchedTransitionMutRef`. + fn first_transition_mut(&mut self) -> Option { + self.transitions + .first_mut() + .map(|transition| transition.borrow_as_mut()) + } +} + +impl DocumentsBatchTransitionMethodsV0 for BatchTransitionV1 { + #[cfg(feature = "state-transition-signing")] + fn new_document_creation_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + entropy: [u8; 32], + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + create_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let owner_id = document.owner_id(); + let create_transition = DocumentCreateTransition::from_document( + document, + document_type, + entropy, + identity_contract_nonce, + platform_version, + create_feature_version, + base_feature_version, + )?; + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Document(create_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_replacement_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + replace_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let owner_id = document.owner_id(); + let replace_transition = DocumentReplaceTransition::from_document( + document, + document_type, + identity_contract_nonce, + platform_version, + replace_feature_version, + base_feature_version, + )?; + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Document(replace_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_transfer_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + recipient_owner_id: Identifier, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + transfer_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let owner_id = document.owner_id(); + let transfer_transition = DocumentTransferTransition::from_document( + document, + document_type, + identity_contract_nonce, + recipient_owner_id, + platform_version, + transfer_feature_version, + base_feature_version, + )?; + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Document(transfer_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_deletion_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + delete_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let owner_id = document.owner_id(); + let delete_transition = DocumentDeleteTransition::from_document( + document, + document_type, + identity_contract_nonce, + platform_version, + delete_feature_version, + base_feature_version, + )?; + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Document(delete_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_update_price_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + update_price_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let owner_id = document.owner_id(); + let transfer_transition = DocumentUpdatePriceTransition::from_document( + document, + document_type, + price, + identity_contract_nonce, + platform_version, + update_price_feature_version, + base_feature_version, + )?; + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Document(transfer_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_document_purchase_transition_from_document( + document: Document, + document_type: DocumentTypeRef, + new_owner_id: Identifier, + price: Credits, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + platform_version: &PlatformVersion, + _batch_feature_version: Option, + purchase_feature_version: Option, + base_feature_version: Option, + ) -> Result { + let purchase_transition = DocumentPurchaseTransition::from_document( + document, + document_type, + price, + identity_contract_nonce, + platform_version, + purchase_feature_version, + base_feature_version, + )?; + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id: new_owner_id, + transitions: vec![BatchedTransition::Document(purchase_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + fn set_transitions(&mut self, transitions: Vec) { + self.transitions = transitions; + } + + fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { + self.transitions + .iter_mut() + .for_each(|transition| transition.set_identity_contract_nonce(identity_contract_nonce)); + } + + fn all_document_purchases_amount(&self) -> Result, ProtocolError> { + let (total, any_purchases): (Option, bool) = self + .transitions + .iter() + .filter_map(|transition| { + transition + .as_transition_purchase() + .map(|purchase| purchase.price()) + }) + .fold((None, false), |(acc, _), price| match acc { + Some(acc_val) => acc_val + .checked_add(price) + .map_or((None, true), |sum| (Some(sum), true)), + None => (Some(price), true), + }); + + match (total, any_purchases) { + (Some(total), _) => Ok(Some(total)), + (None, true) => Err(ProtocolError::Overflow("overflow in all purchases amount")), // Overflow occurred + _ => Ok(None), // No purchases were found + } + } + + fn all_conflicting_index_collateral_voting_funds( + &self, + ) -> Result, ProtocolError> { + let (total, any_voting_funds): (Option, bool) = self + .transitions + .iter() + .filter_map(|transition| { + transition + .as_transition_create() + .and_then(|document_create_transition| { + // Safely sum up values to avoid overflow. + document_create_transition + .prefunded_voting_balance() + .as_ref() + .map(|(_, credits)| *credits) + }) + }) + .fold((None, false), |(acc, _), price| match acc { + Some(acc_val) => acc_val + .checked_add(price) + .map_or((None, true), |sum| (Some(sum), true)), + None => (Some(price), true), + }); + + match (total, any_voting_funds) { + (Some(total), _) => Ok(Some(total)), + (None, true) => Err(ProtocolError::Overflow( + "overflow in all voting funds amount", + )), // Overflow occurred + _ => Ok(None), + } + } +} + +impl DocumentsBatchTransitionMethodsV1 for BatchTransitionV1 { + #[cfg(feature = "state-transition-signing")] + fn new_token_mint_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + issued_to_identity_id: Option, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + let mut mint_transition = TokenMintTransition::V0(TokenMintTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + issued_to_identity_id, + amount, + public_note, + }); + + if let Some(using_group_info_status) = using_group_info { + match using_group_info_status { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => { + let action_id = mint_transition.calculate_action_id(owner_id); + mint_transition.base_mut().set_using_group_info(Some( + GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer: true, + }, + )) + } + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => { + mint_transition.base_mut().set_using_group_info(Some(info)) + } + } + } + + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token(mint_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_burn_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + let mut burn_transition = TokenBurnTransition::V0(TokenBurnTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + burn_amount: amount, + public_note, + }); + + if let Some(using_group_info_status) = using_group_info { + match using_group_info_status { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => { + let action_id = burn_transition.calculate_action_id(owner_id); + burn_transition.base_mut().set_using_group_info(Some( + GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer: true, + }, + )) + } + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => { + burn_transition.base_mut().set_using_group_info(Some(info)) + } + } + } + + // Wrap in a batch transition + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token(burn_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + + // Create the state transition + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + + Ok(state_transition) + } + #[cfg(feature = "state-transition-signing")] + fn new_token_transfer_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + amount: TokenAmount, + recipient_id: Identifier, + public_note: Option, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + // Create the transfer transition for batch version 1 + let transfer_transition = TokenTransferTransition::V0(TokenTransferTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + recipient_id, + amount, + public_note, + shared_encrypted_note, + private_encrypted_note, + }); + + // Wrap in a batch transition + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token(transfer_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + + // Create the state transition + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_freeze_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + let mut freeze_transition = TokenFreezeTransition::V0(TokenFreezeTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + frozen_identity_id, + public_note, + }); + + if let Some(using_group_info_status) = using_group_info { + match using_group_info_status { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => { + let action_id = freeze_transition.calculate_action_id(owner_id); + freeze_transition.base_mut().set_using_group_info(Some( + GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer: true, + }, + )) + } + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => { + freeze_transition + .base_mut() + .set_using_group_info(Some(info)) + } + } + } + + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token(freeze_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_unfreeze_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + let mut unfreeze_transition = TokenUnfreezeTransition::V0(TokenUnfreezeTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + frozen_identity_id, + public_note, + }); + + if let Some(using_group_info_status) = using_group_info { + match using_group_info_status { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => { + let action_id = unfreeze_transition.calculate_action_id(owner_id); + unfreeze_transition.base_mut().set_using_group_info(Some( + GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer: true, + }, + )) + } + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => { + unfreeze_transition + .base_mut() + .set_using_group_info(Some(info)) + } + } + } + + let documents_batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token(unfreeze_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = documents_batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_destroy_frozen_funds_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + frozen_identity_id: Identifier, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + let mut destroy_frozen_funds_transition = + TokenDestroyFrozenFundsTransition::V0(TokenDestroyFrozenFundsTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + frozen_identity_id, + public_note, + }); + + if let Some(using_group_info_status) = using_group_info { + match using_group_info_status { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => { + let action_id = destroy_frozen_funds_transition.calculate_action_id(owner_id); + destroy_frozen_funds_transition + .base_mut() + .set_using_group_info(Some(GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer: true, + })) + } + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => { + destroy_frozen_funds_transition + .base_mut() + .set_using_group_info(Some(info)) + } + } + } + + let batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token( + destroy_frozen_funds_transition.into(), + )], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } + + #[cfg(feature = "state-transition-signing")] + fn new_token_emergency_action_transition( + token_id: Identifier, + owner_id: Identifier, + data_contract_id: Identifier, + token_contract_position: u16, + emergency_action: TokenEmergencyAction, + public_note: Option, + using_group_info: Option, + identity_public_key: &IdentityPublicKey, + identity_contract_nonce: IdentityNonce, + user_fee_increase: UserFeeIncrease, + signer: &S, + _platform_version: &PlatformVersion, + _batch_feature_version: Option, + _delete_feature_version: Option, + _base_feature_version: Option, + ) -> Result { + let mut emergency_action_transition = + TokenEmergencyActionTransition::V0(TokenEmergencyActionTransitionV0 { + base: TokenBaseTransition::V0(TokenBaseTransitionV0 { + identity_contract_nonce, + token_contract_position, + data_contract_id, + token_id, + using_group_info: None, + }), + emergency_action, + public_note, + }); + + if let Some(using_group_info_status) = using_group_info { + match using_group_info_status { + GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer( + group_contract_position, + ) => { + let action_id = emergency_action_transition.calculate_action_id(owner_id); + emergency_action_transition + .base_mut() + .set_using_group_info(Some(GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer: true, + })) + } + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner(info) => { + emergency_action_transition + .base_mut() + .set_using_group_info(Some(info)) + } + } + } + + let batch_transition: BatchTransition = BatchTransitionV1 { + owner_id, + transitions: vec![BatchedTransition::Token(emergency_action_transition.into())], + user_fee_increase, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + let mut state_transition: StateTransition = batch_transition.into(); + state_transition.sign_external( + identity_public_key, + signer, + Some(|_, _| Ok(SecurityLevel::HIGH)), + )?; + Ok(state_transition) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/value_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/value_conversion.rs new file mode 100644 index 0000000000..53a75f0a89 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/value_conversion.rs @@ -0,0 +1,4 @@ +use crate::state_transition::batch_transition::BatchTransitionV1; +use crate::state_transition::StateTransitionValueConvert; + +impl<'a> StateTransitionValueConvert<'a> for BatchTransitionV1 {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/version.rs new file mode 100644 index 0000000000..dcedbd2896 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/v1/version.rs @@ -0,0 +1,9 @@ +use crate::state_transition::batch_transition::BatchTransitionV1; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for BatchTransitionV1 { + fn feature_version(&self) -> FeatureVersion { + 1 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/find_duplicates_by_id/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/find_duplicates_by_id/mod.rs similarity index 84% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/find_duplicates_by_id/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/find_duplicates_by_id/mod.rs index 00206feeb5..ccb6ab1530 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/find_duplicates_by_id/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/find_duplicates_by_id/mod.rs @@ -1,4 +1,4 @@ -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::DocumentTransition; use crate::ProtocolError; use platform_version::version::PlatformVersion; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/find_duplicates_by_id/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/find_duplicates_by_id/v0/mod.rs similarity index 73% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/find_duplicates_by_id/v0/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/find_duplicates_by_id/v0/mod.rs index 71e1b19b29..27f1f46368 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/find_duplicates_by_id/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/find_duplicates_by_id/v0/mod.rs @@ -1,11 +1,8 @@ -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentTransition, DocumentTransitionV0Methods, -}; - +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; use platform_value::Identifier; use std::collections::btree_map::Entry; use std::collections::BTreeMap; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; #[derive(Hash, Eq, PartialEq, Ord, PartialOrd)] struct TransitionFingerprint<'a> { @@ -51,14 +48,14 @@ pub(super) fn find_duplicates_by_id<'a>( #[cfg(test)] mod test { use super::*; - use crate::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; - use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; - use crate::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; - use crate::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; - use crate::state_transition::documents_batch_transition::document_transition::DocumentCreateTransition; - use crate::state_transition::documents_batch_transition::document_transition::DocumentReplaceTransition; - use crate::state_transition::documents_batch_transition::document_transition::DocumentDeleteTransition; - use crate::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; + use crate::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; + use crate::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; + use crate::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; + use crate::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; + use crate::state_transition::batch_transition::batched_transition::DocumentCreateTransition; + use crate::state_transition::batch_transition::batched_transition::DocumentReplaceTransition; + use crate::state_transition::batch_transition::batched_transition::DocumentDeleteTransition; + use crate::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; #[test] fn test_duplicates() { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/mod.rs similarity index 100% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/mod.rs diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/mod.rs similarity index 88% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/mod.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/mod.rs index 6989178211..b2f89c158d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/mod.rs @@ -1,11 +1,11 @@ -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; +use crate::state_transition::batch_transition::BatchTransition; use crate::validation::SimpleConsensusValidationResult; use crate::ProtocolError; use platform_version::version::PlatformVersion; mod v0; -impl DocumentsBatchTransition { +impl BatchTransition { pub fn validate_base_structure( &self, platform_version: &PlatformVersion, 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 new file mode 100644 index 0000000000..c90794beb7 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/validation/validate_basic_structure/v0/mod.rs @@ -0,0 +1,191 @@ +use crate::consensus::basic::document::{ + DocumentTransitionsAreAbsentError, DuplicateDocumentTransitionsWithIdsError, + MaxDocumentsTransitionsExceededError, NonceOutOfBoundsError, +}; +use crate::consensus::basic::BasicError; + +use crate::identity::identity_nonce::MISSING_IDENTITY_REVISIONS_FILTER; +use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use crate::state_transition::batch_transition::validation::find_duplicates_by_id::find_duplicates_by_id; +use crate::state_transition::batch_transition::BatchTransition; +use crate::validation::SimpleConsensusValidationResult; +use crate::ProtocolError; +use platform_value::Identifier; +use platform_version::version::PlatformVersion; +use std::collections::btree_map::Entry; +use std::collections::BTreeMap; +use crate::consensus::basic::group::GroupActionNotAllowedOnTransitionError; +use crate::consensus::basic::token::{InvalidActionIdError, InvalidTokenIdError, TokenTransferToOurselfError}; +use crate::state_transition::batch_transition::batched_transition::BatchedTransitionRef; +use crate::state_transition::batch_transition::batched_transition::token_transition::{TokenTransition, TokenTransitionV0Methods}; +use crate::state_transition::batch_transition::batched_transition::token_transition_action_type::TokenTransitionActionTypeGetter; +use crate::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::state_transition::batch_transition::token_transfer_transition::v0::v0_methods::TokenTransferTransitionV0Methods; +use crate::state_transition::state_transitions::document::batch_transition::batched_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; +use crate::state_transition::StateTransitionLike; + +impl BatchTransition { + #[inline(always)] + pub(super) fn validate_base_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result { + if self.transitions_are_empty() { + return Ok(SimpleConsensusValidationResult::new_with_error( + DocumentTransitionsAreAbsentError::new().into(), + )); + } + + let transitions_len = self.transitions_len(); + + if transitions_len > u16::MAX as usize + || transitions_len as u16 + > platform_version + .system_limits + .max_transitions_in_documents_batch + { + return Ok(SimpleConsensusValidationResult::new_with_error( + MaxDocumentsTransitionsExceededError::new( + platform_version + .system_limits + .max_transitions_in_documents_batch, + ) + .into(), + )); + } + + // Group transitions by contract ID + let mut document_transitions_by_contracts: BTreeMap> = + BTreeMap::new(); + + // Group transitions by contract ID + let mut token_transitions: Vec<&TokenTransition> = vec![]; + + self.transitions_iter() + .for_each(|batch_transition| match batch_transition { + BatchedTransitionRef::Document(document_transition) => { + let contract_identifier = document_transition.data_contract_id(); + + match document_transitions_by_contracts.entry(contract_identifier) { + Entry::Vacant(vacant) => { + vacant.insert(vec![document_transition]); + } + Entry::Occupied(mut identifiers) => { + identifiers.get_mut().push(document_transition); + } + }; + } + BatchedTransitionRef::Token(token_transition) => { + token_transitions.push(token_transition) + } + }); + + let mut result = SimpleConsensusValidationResult::default(); + + for transitions in document_transitions_by_contracts.values() { + for transition in transitions { + // We need to make sure that the identity contract nonce is within the allowed bounds + // This means that it is stored on 40 bits + if transition.identity_contract_nonce() & MISSING_IDENTITY_REVISIONS_FILTER > 0 { + result.add_error(BasicError::NonceOutOfBoundsError( + NonceOutOfBoundsError::new(transition.identity_contract_nonce()), + )); + } + } + + // Make sure we don't have duplicate transitions + let duplicate_transitions = find_duplicates_by_id(transitions, platform_version)?; + + if !duplicate_transitions.is_empty() { + let references: Vec<(String, [u8; 32])> = duplicate_transitions + .into_iter() + .map(|transition| { + Ok(( + transition.base().document_type_name().clone(), + transition.base().id().to_buffer(), + )) + }) + .collect::, anyhow::Error>>()?; + + result.add_error(BasicError::DuplicateDocumentTransitionsWithIdsError( + DuplicateDocumentTransitionsWithIdsError::new(references), + )); + } + } + + for transition in token_transitions { + // We need to make sure that the identity contract nonce is within the allowed bounds + // This means that it is stored on 40 bits + if transition.identity_contract_nonce() & MISSING_IDENTITY_REVISIONS_FILTER > 0 { + result.add_error(BasicError::NonceOutOfBoundsError( + NonceOutOfBoundsError::new(transition.identity_contract_nonce()), + )); + } + + let transition_token_id = transition.base().token_id(); + let calculated_token_id = transition.base().calculate_token_id(); + + // We need to verify that the token id is correct + if transition_token_id != calculated_token_id { + result.add_error(BasicError::InvalidTokenIdError(InvalidTokenIdError::new( + calculated_token_id, + transition_token_id, + ))); + } + + match transition { + TokenTransition::Burn(_) => {} + TokenTransition::Mint(_) => {} + TokenTransition::Transfer(transfer) => { + if transfer.recipient_id() == self.owner_id() { + // We can not transfer to ourselves + result.add_error(BasicError::TokenTransferToOurselfError( + TokenTransferToOurselfError::new( + transition.token_id(), + self.owner_id(), + ), + )); + } + } + TokenTransition::Freeze(_) => {} + TokenTransition::Unfreeze(_) => {} + TokenTransition::DestroyFrozenFunds(_) => {} + TokenTransition::EmergencyAction(_) => {} + } + + // We need to verify that the action id given matches the expected action id + // But only if we are the proposer + if let Some(group_state_transition_info) = transition.base().using_group_info() { + if group_state_transition_info.action_is_proposer { + if let Some(calculated_action_id) = + transition.calculate_action_id(self.owner_id()) + { + if group_state_transition_info.action_id != calculated_action_id { + result.add_error(BasicError::InvalidActionIdError( + InvalidActionIdError::new( + calculated_action_id, + group_state_transition_info.action_id, + ), + )); + } + } else { + result.add_error(BasicError::GroupActionNotAllowedOnTransitionError( + GroupActionNotAllowedOnTransitionError::new( + transition.action_type().to_string(), + ), + )); + } + } else if !transition.can_calculate_action_id() { + result.add_error(BasicError::GroupActionNotAllowedOnTransitionError( + GroupActionNotAllowedOnTransitionError::new( + transition.action_type().to_string(), + ), + )); + } + } + } + + Ok(result) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/value_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/value_conversion.rs similarity index 61% rename from packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/value_conversion.rs rename to packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/value_conversion.rs index 5d02772e07..e9d975ea47 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/value_conversion.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/value_conversion.rs @@ -4,53 +4,73 @@ use platform_value::Value; use crate::ProtocolError; -use crate::state_transition::documents_batch_transition::{ - DocumentsBatchTransition, DocumentsBatchTransitionV0, +use crate::state_transition::batch_transition::{ + BatchTransition, BatchTransitionV0, BatchTransitionV1, }; -use crate::state_transition::state_transitions::documents_batch_transition::fields::*; +use crate::state_transition::state_transitions::batch_transition::fields::*; use crate::state_transition::StateTransitionValueConvert; use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper; use platform_version::version::{FeatureVersion, PlatformVersion}; -impl<'a> StateTransitionValueConvert<'a> for DocumentsBatchTransition { +impl<'a> StateTransitionValueConvert<'a> for BatchTransition { fn to_object(&self, skip_signature: bool) -> Result { match self { - DocumentsBatchTransition::V0(transition) => { + BatchTransition::V0(transition) => { let mut value = transition.to_object(skip_signature)?; value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(0))?; Ok(value) } + BatchTransition::V1(transition) => { + let mut value = transition.to_object(skip_signature)?; + value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(1))?; + Ok(value) + } } } fn to_canonical_object(&self, skip_signature: bool) -> Result { match self { - DocumentsBatchTransition::V0(transition) => { + BatchTransition::V0(transition) => { let mut value = transition.to_canonical_object(skip_signature)?; value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(0))?; Ok(value) } + BatchTransition::V1(transition) => { + let mut value = transition.to_canonical_object(skip_signature)?; + value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(1))?; + Ok(value) + } } } fn to_canonical_cleaned_object(&self, skip_signature: bool) -> Result { match self { - DocumentsBatchTransition::V0(transition) => { + BatchTransition::V0(transition) => { let mut value = transition.to_canonical_cleaned_object(skip_signature)?; value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(0))?; Ok(value) } + BatchTransition::V1(transition) => { + let mut value = transition.to_canonical_cleaned_object(skip_signature)?; + value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(1))?; + Ok(value) + } } } fn to_cleaned_object(&self, skip_signature: bool) -> Result { match self { - DocumentsBatchTransition::V0(transition) => { + BatchTransition::V0(transition) => { let mut value = transition.to_cleaned_object(skip_signature)?; value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(0))?; Ok(value) } + BatchTransition::V1(transition) => { + let mut value = transition.to_cleaned_object(skip_signature)?; + value.insert(STATE_TRANSITION_PROTOCOL_VERSION.to_string(), Value::U16(1))?; + Ok(value) + } } } @@ -70,9 +90,10 @@ impl<'a> StateTransitionValueConvert<'a> for DocumentsBatchTransition { }); match version { - 0 => Ok(DocumentsBatchTransitionV0::from_object(raw_object, platform_version)?.into()), + 0 => Ok(BatchTransitionV0::from_object(raw_object, platform_version)?.into()), + 1 => Ok(BatchTransitionV1::from_object(raw_object, platform_version)?.into()), n => Err(ProtocolError::UnknownVersionError(format!( - "Unknown DataContractCreateTransition version {n}" + "Unknown contract_create_state_transition default_current_version {n}" ))), } } @@ -93,11 +114,10 @@ impl<'a> StateTransitionValueConvert<'a> for DocumentsBatchTransition { }); match version { - 0 => Ok( - DocumentsBatchTransitionV0::from_value_map(raw_value_map, platform_version)?.into(), - ), + 0 => Ok(BatchTransitionV0::from_value_map(raw_value_map, platform_version)?.into()), + 1 => Ok(BatchTransitionV1::from_value_map(raw_value_map, platform_version)?.into()), n => Err(ProtocolError::UnknownVersionError(format!( - "Unknown DataContractCreateTransition version {n}" + "Unknown contract_create_state_transition default_current_version {n}" ))), } } @@ -108,7 +128,8 @@ impl<'a> StateTransitionValueConvert<'a> for DocumentsBatchTransition { .map_err(ProtocolError::ValueError)?; match version { - 0 => DocumentsBatchTransitionV0::clean_value(value), + 0 => BatchTransitionV0::clean_value(value), + 1 => BatchTransitionV1::clean_value(value), n => Err(ProtocolError::UnknownVersionError(format!( "Unknown DataContractCreateTransition version {n}" ))), diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/version.rs new file mode 100644 index 0000000000..be7d07021e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/batch_transition/version.rs @@ -0,0 +1,12 @@ +use crate::state_transition::batch_transition::BatchTransition; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for BatchTransition { + fn feature_version(&self) -> FeatureVersion { + match self { + BatchTransition::V0(v0) => v0.feature_version(), + BatchTransition::V1(v1) => v1.feature_version(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/mod.rs deleted file mode 100644 index 34ae8b57ab..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod v0; - -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -pub use v0::*; - -impl DocumentsBatchTransitionAccessorsV0 for DocumentsBatchTransition { - fn transitions(&self) -> &Vec { - match self { - DocumentsBatchTransition::V0(v0) => &v0.transitions, - } - } - - fn transitions_slice(&self) -> &[DocumentTransition] { - match self { - DocumentsBatchTransition::V0(v0) => v0.transitions.as_slice(), - } - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/v0/mod.rs deleted file mode 100644 index 1e458fad49..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/accessors/v0/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; - -pub trait DocumentsBatchTransitionAccessorsV0 { - fn transitions(&self) -> &Vec; - fn transitions_slice(&self) -> &[DocumentTransition]; -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/v0_methods.rs deleted file mode 100644 index d37685df0d..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/document_transition/document_delete_transition/v0/v0_methods.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; -use crate::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; - -pub trait DocumentDeleteTransitionV0Methods { - /// Returns a reference to the `base` field of the `DocumentCreateTransitionV0`. - fn base(&self) -> &DocumentBaseTransition; - fn base_mut(&mut self) -> &mut DocumentBaseTransition; - - /// Sets the value of the `base` field in the `DocumentCreateTransitionV0`. - /// - /// # Arguments - /// - /// * `base` - A value of type `DocumentBaseTransition` to set. - fn set_base(&mut self, base: DocumentBaseTransition); -} - -impl DocumentDeleteTransitionV0Methods for DocumentDeleteTransitionV0 { - fn base(&self) -> &DocumentBaseTransition { - &self.base - } - - fn base_mut(&mut self) -> &mut DocumentBaseTransition { - &mut self.base - } - - fn set_base(&mut self, base: DocumentBaseTransition) { - self.base = base - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/identity_signed.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/identity_signed.rs deleted file mode 100644 index 3d8a2d1486..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/identity_signed.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::identity::{KeyID, Purpose, SecurityLevel}; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -use crate::state_transition::StateTransitionIdentitySigned; - -impl StateTransitionIdentitySigned for DocumentsBatchTransition { - fn signature_public_key_id(&self) -> KeyID { - match self { - DocumentsBatchTransition::V0(transition) => transition.signature_public_key_id(), - } - } - - fn set_signature_public_key_id(&mut self, key_id: KeyID) { - match self { - DocumentsBatchTransition::V0(transition) => { - transition.set_signature_public_key_id(key_id) - } - } - } - - fn security_level_requirement(&self, purpose: Purpose) -> Vec { - match self { - DocumentsBatchTransition::V0(transition) => { - transition.security_level_requirement(purpose) - } - } - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs deleted file mode 100644 index 071ed54f90..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/methods/mod.rs +++ /dev/null @@ -1,326 +0,0 @@ -#[cfg(feature = "state-transition-signing")] -use crate::data_contract::document_type::DocumentTypeRef; -#[cfg(feature = "state-transition-signing")] -use crate::document::Document; -use crate::fee::Credits; -#[cfg(feature = "state-transition-signing")] -use crate::identity::signer::Signer; -#[cfg(feature = "state-transition-signing")] -use crate::identity::IdentityPublicKey; -use crate::prelude::IdentityNonce; -#[cfg(feature = "state-transition-signing")] -use crate::prelude::UserFeeIncrease; -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; -use crate::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -#[cfg(feature = "state-transition-signing")] -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; -#[cfg(feature = "state-transition-signing")] -use crate::state_transition::StateTransition; -use crate::ProtocolError; -#[cfg(feature = "state-transition-signing")] -use platform_value::Identifier; -#[cfg(feature = "state-transition-signing")] -use platform_version::version::{FeatureVersion, PlatformVersion}; - -pub mod v0; - -impl DocumentsBatchTransitionMethodsV0 for DocumentsBatchTransition { - fn all_purchases_amount(&self) -> Result, ProtocolError> { - match self { - DocumentsBatchTransition::V0(v0) => v0.all_purchases_amount(), - } - } - - fn all_conflicting_index_collateral_voting_funds( - &self, - ) -> Result, ProtocolError> { - match self { - DocumentsBatchTransition::V0(v0) => v0.all_conflicting_index_collateral_voting_funds(), - } - } - - fn set_transitions(&mut self, transitions: Vec) { - match self { - DocumentsBatchTransition::V0(v0) => v0.set_transitions(transitions), - } - } - - fn set_identity_contract_nonce(&mut self, identity_contract_nonce: IdentityNonce) { - match self { - DocumentsBatchTransition::V0(v0) => { - v0.set_identity_contract_nonce(identity_contract_nonce) - } - } - } - - #[cfg(feature = "state-transition-signing")] - fn new_document_creation_transition_from_document( - document: Document, - document_type: DocumentTypeRef, - entropy: [u8; 32], - identity_public_key: &IdentityPublicKey, - identity_contract_nonce: IdentityNonce, - user_fee_increase: UserFeeIncrease, - signer: &S, - platform_version: &PlatformVersion, - batch_feature_version: Option, - create_feature_version: Option, - base_feature_version: Option, - ) -> Result { - match batch_feature_version.unwrap_or( - platform_version - .dpp - .state_transition_serialization_versions - .documents_batch_state_transition - .default_current_version, - ) { - 0 => Ok( - DocumentsBatchTransitionV0::new_document_creation_transition_from_document( - document, - document_type, - entropy, - identity_public_key, - identity_contract_nonce, - user_fee_increase, - signer, - platform_version, - batch_feature_version, - create_feature_version, - base_feature_version, - )?, - ), - version => Err(ProtocolError::UnknownVersionMismatch { - method: "DocumentsBatchTransition::new_created_from_document".to_string(), - known_versions: vec![0], - received: version, - }), - } - } - - #[cfg(feature = "state-transition-signing")] - fn new_document_replacement_transition_from_document( - document: Document, - document_type: DocumentTypeRef, - identity_public_key: &IdentityPublicKey, - identity_contract_nonce: IdentityNonce, - user_fee_increase: UserFeeIncrease, - signer: &S, - platform_version: &PlatformVersion, - batch_feature_version: Option, - replace_feature_version: Option, - base_feature_version: Option, - ) -> Result { - match batch_feature_version.unwrap_or( - platform_version - .dpp - .state_transition_serialization_versions - .documents_batch_state_transition - .default_current_version, - ) { - 0 => Ok( - DocumentsBatchTransitionV0::new_document_replacement_transition_from_document( - document, - document_type, - identity_public_key, - identity_contract_nonce, - user_fee_increase, - signer, - platform_version, - batch_feature_version, - replace_feature_version, - base_feature_version, - )?, - ), - version => Err(ProtocolError::UnknownVersionMismatch { - method: - "DocumentsBatchTransition::new_document_replacement_transition_from_document" - .to_string(), - known_versions: vec![0], - received: version, - }), - } - } - - #[cfg(feature = "state-transition-signing")] - fn new_document_transfer_transition_from_document( - document: Document, - document_type: DocumentTypeRef, - recipient_owner_id: Identifier, - identity_public_key: &IdentityPublicKey, - identity_contract_nonce: IdentityNonce, - user_fee_increase: UserFeeIncrease, - signer: &S, - platform_version: &PlatformVersion, - batch_feature_version: Option, - transfer_feature_version: Option, - base_feature_version: Option, - ) -> Result { - match batch_feature_version.unwrap_or( - platform_version - .dpp - .state_transition_serialization_versions - .documents_batch_state_transition - .default_current_version, - ) { - 0 => Ok( - DocumentsBatchTransitionV0::new_document_transfer_transition_from_document( - document, - document_type, - recipient_owner_id, - identity_public_key, - identity_contract_nonce, - user_fee_increase, - signer, - platform_version, - batch_feature_version, - transfer_feature_version, - base_feature_version, - )?, - ), - version => Err(ProtocolError::UnknownVersionMismatch { - method: - "DocumentsBatchTransition::new_document_replacement_transition_from_document" - .to_string(), - known_versions: vec![0], - received: version, - }), - } - } - - #[cfg(feature = "state-transition-signing")] - fn new_document_deletion_transition_from_document( - document: Document, - document_type: DocumentTypeRef, - identity_public_key: &IdentityPublicKey, - identity_contract_nonce: IdentityNonce, - user_fee_increase: UserFeeIncrease, - signer: &S, - platform_version: &PlatformVersion, - batch_feature_version: Option, - delete_feature_version: Option, - base_feature_version: Option, - ) -> Result { - match batch_feature_version.unwrap_or( - platform_version - .dpp - .state_transition_serialization_versions - .documents_batch_state_transition - .default_current_version, - ) { - 0 => Ok( - DocumentsBatchTransitionV0::new_document_deletion_transition_from_document( - document, - document_type, - identity_public_key, - identity_contract_nonce, - user_fee_increase, - signer, - platform_version, - batch_feature_version, - delete_feature_version, - base_feature_version, - )?, - ), - version => Err(ProtocolError::UnknownVersionMismatch { - method: "DocumentsBatchTransition::new_document_deletion_transition_from_document" - .to_string(), - known_versions: vec![0], - received: version, - }), - } - } - - #[cfg(feature = "state-transition-signing")] - fn new_document_update_price_transition_from_document( - document: Document, - document_type: DocumentTypeRef, - price: Credits, - identity_public_key: &IdentityPublicKey, - identity_contract_nonce: IdentityNonce, - user_fee_increase: UserFeeIncrease, - signer: &S, - platform_version: &PlatformVersion, - batch_feature_version: Option, - update_price_feature_version: Option, - base_feature_version: Option, - ) -> Result { - match batch_feature_version.unwrap_or( - platform_version - .dpp - .state_transition_serialization_versions - .documents_batch_state_transition - .default_current_version, - ) { - 0 => Ok( - DocumentsBatchTransitionV0::new_document_update_price_transition_from_document( - document, - document_type, - price, - identity_public_key, - identity_contract_nonce, - user_fee_increase, - signer, - platform_version, - batch_feature_version, - update_price_feature_version, - base_feature_version, - )?, - ), - version => Err(ProtocolError::UnknownVersionMismatch { - method: - "DocumentsBatchTransition::new_document_update_price_transition_from_document" - .to_string(), - known_versions: vec![0], - received: version, - }), - } - } - - #[cfg(feature = "state-transition-signing")] - fn new_document_purchase_transition_from_document( - document: Document, - document_type: DocumentTypeRef, - new_owner_id: Identifier, - price: Credits, - identity_public_key: &IdentityPublicKey, - identity_contract_nonce: IdentityNonce, - user_fee_increase: UserFeeIncrease, - signer: &S, - platform_version: &PlatformVersion, - batch_feature_version: Option, - purchase_feature_version: Option, - base_feature_version: Option, - ) -> Result { - match batch_feature_version.unwrap_or( - platform_version - .dpp - .state_transition_serialization_versions - .documents_batch_state_transition - .default_current_version, - ) { - 0 => Ok( - DocumentsBatchTransitionV0::new_document_purchase_transition_from_document( - document, - document_type, - new_owner_id, - price, - identity_public_key, - identity_contract_nonce, - user_fee_increase, - signer, - platform_version, - batch_feature_version, - purchase_feature_version, - base_feature_version, - )?, - ), - version => Err(ProtocolError::UnknownVersionMismatch { - method: "DocumentsBatchTransition::new_document_purchase_transition_from_document" - .to_string(), - known_versions: vec![0], - received: version, - }), - } - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/mod.rs deleted file mode 100644 index f62e971fb7..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/mod.rs +++ /dev/null @@ -1,598 +0,0 @@ -use bincode::{Decode, Encode}; - -use std::convert::TryInto; - -use derive_more::From; - -use platform_value::Value; -#[cfg(feature = "state-transition-serde-conversion")] -use serde::{Deserialize, Serialize}; - -use crate::ProtocolError; -use crate::{identity::SecurityLevel, state_transition::StateTransitionFieldTypes}; - -pub use self::document_transition::{ - document_base_transition, document_create_transition, - document_create_transition::DocumentCreateTransition, document_delete_transition, - document_delete_transition::DocumentDeleteTransition, document_replace_transition, - document_replace_transition::DocumentReplaceTransition, -}; - -use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; -use platform_versioning::PlatformVersioned; - -pub mod accessors; -pub mod document_transition; -pub mod fields; -mod identity_signed; -#[cfg(feature = "state-transition-json-conversion")] -mod json_conversion; -pub mod methods; -mod state_transition_like; -mod v0; -#[cfg(feature = "validation")] -mod validation; -#[cfg(feature = "state-transition-value-conversion")] -mod value_conversion; -mod version; - -use crate::state_transition::data_contract_update_transition::{ - SIGNATURE, SIGNATURE_PUBLIC_KEY_ID, -}; - -use crate::state_transition::documents_batch_transition::fields::property_names; - -use crate::identity::state_transition::OptionallyAssetLockProved; -pub use v0::*; - -#[derive( - Debug, - Clone, - PartialEq, - Encode, - Decode, - PlatformDeserialize, - PlatformSerialize, - PlatformSignable, - PlatformVersioned, - From, -)] -#[cfg_attr( - feature = "state-transition-serde-conversion", - derive(Serialize, Deserialize), - serde(tag = "$version") -)] -#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version -#[platform_version_path_bounds( - "dpp.state_transition_serialization_versions.documents_batch_state_transition" -)] -pub enum DocumentsBatchTransition { - #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] - V0(DocumentsBatchTransitionV0), -} - -// -// impl Default for DocumentsBatchTransition { -// fn default() -> Self { -// match LATEST_PLATFORM_VERSION -// .state_transitions -// .documents_batch_state_transition -// .default_current_version -// { -// 0 => DocumentsBatchTransitionV0::default().into(), -// _ => DocumentsBatchTransitionV0::default().into(), //for now -// } -// } -// } -// -// impl DocumentsBatchTransition { -// #[cfg(feature = "state-transition-json-conversion")] -// pub fn from_json_object( -// json_value: JsonValue, -// data_contracts: Vec, -// ) -> Result { -// let mut json_value = json_value; -// -// let maybe_signature = json_value.get_string(property_names::SIGNATURE).ok(); -// let signature = if let Some(signature) = maybe_signature { -// Some(BinaryData( -// BASE64_STANDARD.decode(signature).context("signature exists but isn't valid base64")?, -// )) -// } else { -// None -// }; -// -// let mut batch_transitions = DocumentsBatchTransition { -// feature_version: json_value -// .get_u64(property_names::STATE_TRANSITION_PROTOCOL_VERSION) -// // js-dpp allows `protocolVersion` to be undefined -// .unwrap_or(LATEST_VERSION as u64) as u16, -// signature, -// signature_public_key_id: json_value -// .get_u64(property_names::SIGNATURE_PUBLIC_KEY_ID) -// .ok() -// .map(|v| v as KeyID), -// owner_id: Identifier::from_string( -// json_value.get_string(property_names::OWNER_ID)?, -// Encoding::Base58, -// )?, -// ..Default::default() -// }; -// -// let mut document_transitions: Vec = vec![]; -// let maybe_transitions = json_value.remove(property_names::TRANSITIONS); -// if let Ok(JsonValue::Array(json_transitions)) = maybe_transitions { -// let data_contracts_map: HashMap, DataContract> = data_contracts -// .into_iter() -// .map(|dc| (dc.id.as_bytes().to_vec(), dc)) -// .collect(); -// -// for json_transition in json_transitions { -// let id = Identifier::from_string( -// json_transition.get_string(property_names::DATA_CONTRACT_ID)?, -// Encoding::Base58, -// )?; -// let data_contract = -// data_contracts_map -// .get(&id.as_bytes().to_vec()) -// .ok_or_else(|| { -// anyhow!( -// "Data Contract doesn't exists for Transition: {:?}", -// json_transition -// ) -// })?; -// let document_transition = -// DocumentTransition::from_json_object(json_transition, data_contract.clone())?; -// document_transitions.push(document_transition); -// } -// } -// -// batch_transitions.transitions = document_transitions; -// Ok(batch_transitions) -// } -// -// /// creates the instance of [`DocumentsBatchTransition`] from raw object -// pub fn from_object_with_contracts( -// raw_object: Value, -// data_contracts: Vec, -// ) -> Result { -// let map = raw_object -// .into_btree_string_map() -// .map_err(ProtocolError::ValueError)?; -// Self::from_value_map(map, data_contracts) -// } -// -// /// creates the instance of [`DocumentsBatchTransition`] from a value map -// pub fn from_value_map( -// mut map: BTreeMap, -// data_contracts: Vec, -// ) -> Result { -// let mut batch_transitions = DocumentsBatchTransition { -// feature_version: map -// .get_integer(property_names::STATE_TRANSITION_PROTOCOL_VERSION) -// // js-dpp allows `protocolVersion` to be undefined -// .unwrap_or(LATEST_VERSION as u64) as u16, -// signature: map -// .get_optional_binary_data(property_names::SIGNATURE) -// .map_err(ProtocolError::ValueError)?, -// signature_public_key_id: map -// .get_optional_integer(property_names::SIGNATURE_PUBLIC_KEY_ID) -// .map_err(ProtocolError::ValueError)?, -// owner_id: Identifier::from( -// map.get_hash256_bytes(property_names::OWNER_ID) -// .map_err(ProtocolError::ValueError)?, -// ), -// ..Default::default() -// }; -// -// let mut document_transitions: Vec = vec![]; -// let maybe_transitions = map.remove(property_names::TRANSITIONS); -// if let Some(Value::Array(raw_transitions)) = maybe_transitions { -// let data_contracts_map: HashMap, DataContract> = data_contracts -// .into_iter() -// .map(|dc| (dc.id.as_bytes().to_vec(), dc)) -// .collect(); -// -// for raw_transition in raw_transitions { -// let mut raw_transition_map = raw_transition -// .into_btree_string_map() -// .map_err(ProtocolError::ValueError)?; -// let data_contract_id = -// raw_transition_map.get_hash256_bytes(property_names::DATA_CONTRACT_ID)?; -// let document_type = raw_transition_map.get_str(property_names::DOCUMENT_TYPE)?; -// let data_contract = data_contracts_map -// .get(data_contract_id.as_slice()) -// .ok_or_else(|| { -// anyhow!( -// "Data Contract doesn't exists for Transition: {:?}", -// raw_transition_map -// ) -// })?; -// -// //Because we don't know how the json came in we need to sanitize it -// let (identifiers, binary_paths): (Vec<_>, Vec<_>) = -// data_contract.get_identifiers_and_binary_paths_owned(document_type)?; -// -// raw_transition_map -// .replace_at_paths( -// identifiers.into_iter().chain( -// document_base_transition::IDENTIFIER_FIELDS -// .iter() -// .map(|a| a.to_string()), -// ), -// ReplacementType::Identifier, -// ) -// .map_err(ProtocolError::ValueError)?; -// raw_transition_map -// .replace_at_paths( -// binary_paths.into_iter().chain( -// document_create_transition::BINARY_FIELDS -// .iter() -// .map(|a| a.to_string()), -// ), -// ReplacementType::BinaryBytes, -// ) -// .map_err(ProtocolError::ValueError)?; -// -// let document_transition = -// DocumentTransition::from_value_map(raw_transition_map, data_contract.clone())?; -// document_transitions.push(document_transition); -// } -// } -// -// batch_transitions.transitions = document_transitions; -// Ok(batch_transitions) -// } -// -// pub fn transitions(&self) -> &Vec { -// &self.transitions -// } -// -// pub fn transitions_slice(&self) -> &[DocumentTransition] { -// self.transitions.as_slice() -// } -// -// pub fn clean_value(value: &mut Value) -> Result<(), platform_value::Error> { -// value.replace_at_paths(IDENTIFIER_FIELDS, ReplacementType::Identifier)?; -// value.replace_integer_type_at_paths(U16_FIELDS, IntegerReplacementType::U16)?; -// Ok(()) -// } -// } -// -// -// impl DocumentsBatchTransition { -// fn to_value(&self, skip_signature: bool) -> Result { -// Ok(self.to_value_map(skip_signature)?.into()) -// } -// -// fn to_value_map(&self, skip_signature: bool) -> Result, ProtocolError> { -// let mut map = BTreeMap::new(); -// map.insert( -// property_names::STATE_TRANSITION_PROTOCOL_VERSION.to_string(), -// Value::U16(self.feature_version), -// ); -// map.insert( -// property_names::TRANSITION_TYPE.to_string(), -// Value::U8(self.transition_type as u8), -// ); -// map.insert( -// property_names::OWNER_ID.to_string(), -// Value::Identifier(self.owner_id.to_buffer()), -// ); -// -// if !skip_signature { -// if let Some(signature) = self.signature.as_ref() { -// map.insert( -// property_names::SIGNATURE.to_string(), -// Value::Bytes(signature.to_vec()), -// ); -// } -// if let Some(signature_key_id) = self.signature_public_key_id { -// map.insert( -// property_names::SIGNATURE.to_string(), -// Value::U32(signature_key_id), -// ); -// } -// } -// let mut transitions = vec![]; -// for transition in self.transitions.iter() { -// transitions.push(transition.to_object()?) -// } -// map.insert( -// property_names::TRANSITIONS.to_string(), -// Value::Array(transitions), -// ); -// -// Ok(map) -// } -// } - -impl StateTransitionFieldTypes for DocumentsBatchTransition { - fn binary_property_paths() -> Vec<&'static str> { - vec![SIGNATURE] - } - - fn identifiers_property_paths() -> Vec<&'static str> { - vec![property_names::OWNER_ID] - } - - fn signature_property_paths() -> Vec<&'static str> { - vec![SIGNATURE, SIGNATURE_PUBLIC_KEY_ID] - } - // - // fn to_json(&self, skip_signature: bool) -> Result { - // self.to_object(skip_signature) - // .and_then(|value| value.try_into().map_err(ProtocolError::ValueError)) - // } - // - // fn to_object(&self, skip_signature: bool) -> Result { - // let mut object: Value = platform_value::to_value(self)?; - // if skip_signature { - // for path in Self::signature_property_paths() { - // let _ = object.remove_values_matching_path(path); - // } - // } - // let mut transitions = vec![]; - // for transition in self.transitions.iter() { - // transitions.push(transition.to_object()?) - // } - // object.insert( - // String::from(property_names::TRANSITIONS), - // Value::Array(transitions), - // )?; - // - // Ok(object) - // } - // - // #[cfg(feature = "state-transition-cbor-conversion")] - // fn to_cbor_buffer(&self, skip_signature: bool) -> Result, ProtocolError> { - // let mut result_buf = self.feature_version.encode_var_vec(); - // let value: CborValue = self.to_object(skip_signature)?.try_into()?; - // - // let map = CborValue::serialized(&value) - // .map_err(|e| ProtocolError::EncodingError(e.to_string()))?; - // - // let mut canonical_map: CborCanonicalMap = map.try_into()?; - // canonical_map.remove(property_names::STATE_TRANSITION_PROTOCOL_VERSION); - // - // // Replace binary fields individually for every transition using respective data contract - // if let Some(CborValue::Array(ref mut transitions)) = - // canonical_map.get_mut(&CborValue::Text(property_names::TRANSITIONS.to_string())) - // { - // for (i, cbor_transition) in transitions.iter_mut().enumerate() { - // let transition = self - // .transitions - // .get(i) - // .context(format!("transition with index {} doesn't exist", i))?; - // - // let (identifier_properties, binary_properties) = transition - // .base() - // .data_contract - // .get_identifiers_and_binary_paths( - // &self.transitions[i].base().document_type_name, - // )?; - // - // if transition.get_updated_at().is_none() { - // cbor_transition.remove("$updatedAt"); - // } - // - // cbor_transition.replace_paths( - // identifier_properties - // .into_iter() - // .chain(binary_properties) - // .chain(document_base_transition::IDENTIFIER_FIELDS) - // .chain(document_create_transition::BINARY_FIELDS), - // FieldType::ArrayInt, - // FieldType::Bytes, - // ); - // } - // } - // - // canonical_map.replace_paths( - // Self::binary_property_paths() - // .into_iter() - // .chain(Self::identifiers_property_paths()), - // FieldType::ArrayInt, - // FieldType::Bytes, - // ); - // - // if !skip_signature { - // if self.signature.is_none() { - // canonical_map.insert(property_names::SIGNATURE, CborValue::Null) - // } - // if self.signature_public_key_id.is_none() { - // canonical_map.insert(property_names::SIGNATURE_PUBLIC_KEY_ID, CborValue::Null) - // } - // } - // - // canonical_map.sort_canonical(); - // - // let mut buffer = canonical_map - // .to_bytes() - // .map_err(|e| ProtocolError::EncodingError(e.to_string()))?; - // result_buf.append(&mut buffer); - // - // Ok(result_buf) - // } - // - // fn to_cleaned_object(&self, skip_signature: bool) -> Result { - // let mut object: Value = platform_value::to_value(self)?; - // if skip_signature { - // for path in Self::signature_property_paths() { - // let _ = object.remove_values_matching_path(path); - // } - // } - // let mut transitions = vec![]; - // for transition in self.transitions.iter() { - // transitions.push(transition.to_cleaned_object()?) - // } - // object.insert( - // String::from(property_names::TRANSITIONS), - // Value::Array(transitions), - // )?; - // - // Ok(object) - // } -} - -// TODO: Make a DocumentType method -pub fn get_security_level_requirement(v: &Value, default: SecurityLevel) -> SecurityLevel { - let maybe_security_level: Option = v - .get_optional_integer(property_names::SECURITY_LEVEL_REQUIREMENT) - // TODO: Data Contract must already valid so there is no chance that this will fail - .expect("document schema must be a map"); - - match maybe_security_level { - Some(some_level) => (some_level as u8).try_into().unwrap_or(default), - None => default, - } -} -// -// #[cfg(test)] -// mod test { -// use itertools::Itertools; -// use std::sync::Arc; -// -// use platform_value::Bytes32; -// use serde_json::json; -// -// use crate::tests::fixtures::get_extended_documents_fixture; -// use crate::{ -// document::{ -// document_factory::DocumentFactory, -// fetch_and_validate_data_contract::DataContractFetcherAndValidator, -// }, -// state_repository::MockStateRepositoryLike, -// tests::fixtures::{ -// get_data_contract_fixture, get_document_transitions_fixture, -// get_document_validator_fixture, -// }, -// }; -// -// use super::{document_transition::Action, *}; -// -// #[test] -// fn should_return_highest_sec_level_for_all_transitions() { -// let mut data_contract = get_data_contract_fixture(None).data_contract; -// data_contract -// .documents -// .get_mut("niceDocument") -// .unwrap() -// .insert( -// property_names::SECURITY_LEVEL_REQUIREMENT.to_string(), -// json!(SecurityLevel::MEDIUM), -// ) -// .unwrap(); -// data_contract -// .documents -// .get_mut("prettyDocument") -// .unwrap() -// .insert( -// property_names::SECURITY_LEVEL_REQUIREMENT.to_string(), -// json!(SecurityLevel::MASTER), -// ) -// .unwrap(); -// -// // 0 is niceDocument, -// // 1 and 2 are pretty documents, -// // 3 and 4 are indexed documents that do not have security level specified -// let documents = get_extended_documents_fixture(data_contract).unwrap(); -// let medium_security_document = documents.get(0).unwrap(); -// let master_security_document = documents.get(1).unwrap(); -// let no_security_level_document = documents.get(3).unwrap(); -// -// let document_factory = DocumentFactory::new( -// 1, -// get_document_validator_fixture(), -// DataContractFetcherAndValidator::new(Arc::new(MockStateRepositoryLike::new())), -// ); -// -// let batch_transition = document_factory -// .create_state_transition(vec![( -// Action::Create, -// vec![medium_security_document.to_owned()], -// )]) -// .expect("batch transition should be created"); -// -// assert!(batch_transition -// .get_security_level_requirement() -// .iter() -// .contains(&SecurityLevel::MEDIUM)); -// -// let batch_transition = document_factory -// .create_state_transition(vec![( -// Action::Create, -// vec![ -// medium_security_document.to_owned(), -// master_security_document.to_owned(), -// ], -// )]) -// .expect("batch transition should be created"); -// -// assert!(batch_transition -// .get_security_level_requirement() -// .iter() -// .contains(&SecurityLevel::MASTER)); -// -// let batch_transition = document_factory -// .create_state_transition(vec![( -// Action::Create, -// vec![no_security_level_document.to_owned()], -// )]) -// .expect("batch transition should be created"); -// -// assert!(batch_transition -// .get_security_level_requirement() -// .iter() -// .contains(&SecurityLevel::HIGH)); -// } -// -// #[test] -// fn should_convert_to_batch_transition_to_the_buffer() { -// let transition_id_base58 = "6o8UfoeE2s7dTkxxyPCixuxe8TM5DtCGHTMummUN6t5M"; -// let expected_bytes_hex ="01a5647479706501676f776e657249645820a858bdc49c968148cd12648ee048d34003e9da3fbf2cbc62c31bb4c717bf690d697369676e6174757265f76b7472616e736974696f6e7381a7632469645820561b9b2e90b7c0ca355f729777b45bc646a18f5426a9462f0333c766135a3120646e616d656543757469656524747970656c6e696365446f63756d656e746724616374696f6e006824656e74726f707958202cdbaeda81c14765ba48432ff5cc900a7cacd4538b817fc71f38907aaa7023746a246372656174656441741b000001853a3602876f2464617461436f6e74726163744964582049aea5df2124a51d5d8dcf466e238fbc77fd72601be69daeb6dba75e8d26b30c747369676e61747572655075626c69634b65794964f7" ; -// let data_contract_id_base58 = "5xdDqypFMPfvF6UdWxefCGvRFyxgkPZCAK6TS4pvvw6T"; -// let owner_id_base58 = "CL9ydpdxP4kQniGx6z5JUL8K72gnwcemKT2aJmh7sdwJ"; -// let entropy_base64 = "LNuu2oHBR2W6SEMv9cyQCnys1FOLgX/HHziQeqpwI3Q="; -// -// let transition_id = -// Identifier::from_string(transition_id_base58, Encoding::Base58).unwrap(); -// let expected_bytes = hex::decode(expected_bytes_hex).unwrap(); -// let data_contract_id = -// Identifier::from_string(data_contract_id_base58, Encoding::Base58).unwrap(); -// let owner_id = Identifier::from_string(owner_id_base58, Encoding::Base58).unwrap(); -// let entropy_bytes: [u8; 32] = BASE64_STANDARD.decode(entropy_base64).unwrap().try_into().unwrap(); -// -// let mut data_contract = get_data_contract_fixture(Some(owner_id)).data_contract; -// data_contract.id = data_contract_id; -// -// let documents = get_extended_documents_fixture(data_contract.clone()).unwrap(); -// let mut document = documents.first().unwrap().to_owned(); -// document.entropy = Bytes32::new(entropy_bytes); -// -// let transitions = get_document_transitions_fixture([(DocumentTransitionActionType::Create, vec![document])]); -// let mut transition = transitions.first().unwrap().to_owned(); -// if let DocumentTransition::Create(ref mut t) = transition { -// t.created_at = Some(1671718896263); -// t.base.id = transition_id; -// } -// -// let mut map = BTreeMap::new(); -// map.insert( -// "ownerId".to_string(), -// Value::Identifier(owner_id.to_buffer()), -// ); -// map.insert( -// "transitions".to_string(), -// Value::Array(vec![transition.to_object().unwrap()]), -// ); -// -// let state_transition = DocumentsBatchTransition::from_value_map(map, vec![data_contract]) -// .expect("transition should be created"); -// -// let bytes = state_transition.to_cbor_buffer(false).unwrap(); -// -// assert_eq!(hex::encode(expected_bytes), hex::encode(bytes)); -// } -// } -impl OptionallyAssetLockProved for DocumentsBatchTransition {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/state_transition_like.rs deleted file mode 100644 index 69b5bfa571..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/state_transition_like.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::prelude::UserFeeIncrease; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -use crate::state_transition::{StateTransitionLike, StateTransitionType}; -use crate::version::FeatureVersion; -use platform_value::{BinaryData, Identifier}; - -impl StateTransitionLike for DocumentsBatchTransition { - /// Returns ID of the created contract - fn modified_data_ids(&self) -> Vec { - match self { - DocumentsBatchTransition::V0(transition) => transition.modified_data_ids(), - } - } - - fn state_transition_protocol_version(&self) -> FeatureVersion { - match self { - DocumentsBatchTransition::V0(_) => 0, - } - } - /// returns the type of State Transition - fn state_transition_type(&self) -> StateTransitionType { - match self { - DocumentsBatchTransition::V0(transition) => transition.state_transition_type(), - } - } - /// returns the signature as a byte-array - fn signature(&self) -> &BinaryData { - match self { - DocumentsBatchTransition::V0(transition) => transition.signature(), - } - } - /// set a new signature - fn set_signature(&mut self, signature: BinaryData) { - match self { - DocumentsBatchTransition::V0(transition) => transition.set_signature(signature), - } - } - - fn set_signature_bytes(&mut self, signature: Vec) { - match self { - DocumentsBatchTransition::V0(transition) => transition.set_signature_bytes(signature), - } - } - - /// returns the fee multiplier - fn user_fee_increase(&self) -> UserFeeIncrease { - match self { - DocumentsBatchTransition::V0(transition) => transition.user_fee_increase(), - } - } - /// set a fee multiplier - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - match self { - DocumentsBatchTransition::V0(transition) => { - transition.set_user_fee_increase(user_fee_increase) - } - } - } - - fn owner_id(&self) -> Identifier { - match self { - DocumentsBatchTransition::V0(transition) => transition.owner_id(), - } - } - - fn unique_identifiers(&self) -> Vec { - match self { - DocumentsBatchTransition::V0(transition) => transition.unique_identifiers(), - } - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/json_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/json_conversion.rs deleted file mode 100644 index ac62cb41c7..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/json_conversion.rs +++ /dev/null @@ -1,4 +0,0 @@ -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; -use crate::state_transition::StateTransitionJsonConvert; - -impl<'a> StateTransitionJsonConvert<'a> for DocumentsBatchTransitionV0 {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/value_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/value_conversion.rs deleted file mode 100644 index d82f708df4..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/v0/value_conversion.rs +++ /dev/null @@ -1,4 +0,0 @@ -use crate::state_transition::documents_batch_transition::DocumentsBatchTransitionV0; -use crate::state_transition::StateTransitionValueConvert; - -impl<'a> StateTransitionValueConvert<'a> for DocumentsBatchTransitionV0 {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/v0/mod.rs deleted file mode 100644 index 1bc2dd8b51..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/validation/validate_basic_structure/v0/mod.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::consensus::basic::document::{ - DocumentTransitionsAreAbsentError, DuplicateDocumentTransitionsWithIdsError, - MaxDocumentsTransitionsExceededError, NonceOutOfBoundsError, -}; -use crate::consensus::basic::BasicError; - -use crate::identity::identity_nonce::MISSING_IDENTITY_REVISIONS_FILTER; -use crate::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use crate::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use crate::state_transition::documents_batch_transition::document_transition::{ - DocumentTransition, DocumentTransitionV0Methods, -}; -use crate::state_transition::documents_batch_transition::validation::find_duplicates_by_id::find_duplicates_by_id; -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -use crate::validation::SimpleConsensusValidationResult; -use crate::ProtocolError; -use platform_value::Identifier; -use platform_version::version::PlatformVersion; -use std::collections::btree_map::Entry; -use std::collections::BTreeMap; - -impl DocumentsBatchTransition { - #[inline(always)] - pub(super) fn validate_base_structure_v0( - &self, - platform_version: &PlatformVersion, - ) -> Result { - if self.transitions().is_empty() { - return Ok(SimpleConsensusValidationResult::new_with_error( - DocumentTransitionsAreAbsentError::new().into(), - )); - } - - let transitions_len = self.transitions().len(); - - if transitions_len > u16::MAX as usize - || transitions_len as u16 - > platform_version - .system_limits - .max_transitions_in_documents_batch - { - return Ok(SimpleConsensusValidationResult::new_with_error( - MaxDocumentsTransitionsExceededError::new( - platform_version - .system_limits - .max_transitions_in_documents_batch, - ) - .into(), - )); - } - - // Group transitions by contract ID - let mut document_transitions_by_contracts: BTreeMap> = - BTreeMap::new(); - - self.transitions().iter().for_each(|document_transition| { - let contract_identifier = document_transition.data_contract_id(); - - match document_transitions_by_contracts.entry(contract_identifier) { - Entry::Vacant(vacant) => { - vacant.insert(vec![document_transition]); - } - Entry::Occupied(mut identifiers) => { - identifiers.get_mut().push(document_transition); - } - }; - }); - - let mut result = SimpleConsensusValidationResult::default(); - - for transitions in document_transitions_by_contracts.values() { - for transition in transitions { - // We need to make sure that the identity contract nonce is within the allowed bounds - // This means that it is stored on 40 bits - if transition.identity_contract_nonce() & MISSING_IDENTITY_REVISIONS_FILTER > 0 { - result.add_error(BasicError::NonceOutOfBoundsError( - NonceOutOfBoundsError::new(transition.identity_contract_nonce()), - )); - } - } - - // Make sure we don't have duplicate transitions - let duplicate_transitions = find_duplicates_by_id(transitions, platform_version)?; - - if !duplicate_transitions.is_empty() { - let references: Vec<(String, [u8; 32])> = duplicate_transitions - .into_iter() - .map(|transition| { - Ok(( - transition.base().document_type_name().clone(), - transition.base().id().to_buffer(), - )) - }) - .collect::, anyhow::Error>>()?; - - result.add_error(BasicError::DuplicateDocumentTransitionsWithIdsError( - DuplicateDocumentTransitionsWithIdsError::new(references), - )); - } - } - - Ok(result) - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/version.rs deleted file mode 100644 index f65071aabe..0000000000 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/documents_batch_transition/version.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::state_transition::documents_batch_transition::DocumentsBatchTransition; -use crate::state_transition::FeatureVersioned; -use crate::version::FeatureVersion; - -impl FeatureVersioned for DocumentsBatchTransition { - fn feature_version(&self) -> FeatureVersion { - match self { - DocumentsBatchTransition::V0(v0) => v0.feature_version(), - } - } -} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/document/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/document/mod.rs index 01a4fd6ffd..03238bee69 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/document/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/document/mod.rs @@ -1 +1 @@ -pub mod documents_batch_transition; +pub mod batch_transition; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs index 588fafe2c0..b68cd97892 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/methods/v0/mod.rs @@ -6,6 +6,8 @@ use crate::{ ProtocolError, }; #[cfg(feature = "state-transition-signing")] +use platform_value::Identifier; +#[cfg(feature = "state-transition-signing")] use platform_version::version::{FeatureVersion, PlatformVersion}; use crate::state_transition::StateTransitionType; @@ -14,7 +16,7 @@ pub trait IdentityCreditTransferTransitionMethodsV0 { #[cfg(feature = "state-transition-signing")] fn try_from_identity( identity: &Identity, - to_identity_with_identifier: platform_value::Identifier, + to_identity_with_identifier: Identifier, amount: u64, user_fee_increase: UserFeeIncrease, signer: S, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs index cf376b9b83..bbcd3780c0 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_transition/v0/v0_methods.rs @@ -8,10 +8,12 @@ use crate::{ state_transition::StateTransition, ProtocolError, }; +#[cfg(feature = "state-transition-signing")] use platform_value::Identifier; use crate::state_transition::identity_credit_transfer_transition::methods::IdentityCreditTransferTransitionMethodsV0; use crate::state_transition::identity_credit_transfer_transition::v0::IdentityCreditTransferTransitionV0; +#[cfg(feature = "state-transition-signing")] use crate::state_transition::GetDataContractSecurityLevelRequirementFn; #[cfg(feature = "state-transition-signing")] use platform_version::version::{FeatureVersion, PlatformVersion}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/value_conversion.rs b/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/value_conversion.rs index 2ebc3b6f85..6822f7d2c3 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/value_conversion.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/identity/public_key_in_creation/value_conversion.rs @@ -1,5 +1,5 @@ use crate::serialization::ValueConvertible; -use crate::state_transition::documents_batch_transition::fields::property_names::STATE_TRANSITION_PROTOCOL_VERSION; +use crate::state_transition::batch_transition::fields::property_names::STATE_TRANSITION_PROTOCOL_VERSION; use crate::state_transition::public_key_in_creation::v0::IdentityPublicKeyInCreationV0; use crate::state_transition::public_key_in_creation::IdentityPublicKeyInCreation; use crate::state_transition::StateTransitionValueConvert; diff --git a/packages/rs-dpp/src/state_transition/traits/state_transition_like.rs b/packages/rs-dpp/src/state_transition/traits/state_transition_like.rs index 4884fd46b6..e3084b6310 100644 --- a/packages/rs-dpp/src/state_transition/traits/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/traits/state_transition_like.rs @@ -8,8 +8,7 @@ use crate::version::FeatureVersion; use crate::state_transition::StateTransitionType; use crate::state_transition::{StateTransition, StateTransitionFieldTypes}; -pub const DOCUMENT_TRANSITION_TYPES: [StateTransitionType; 1] = - [StateTransitionType::DocumentsBatch]; +pub const DOCUMENT_TRANSITION_TYPES: [StateTransitionType; 1] = [StateTransitionType::Batch]; pub const IDENTITY_TRANSITION_TYPE: [StateTransitionType; 5] = [ StateTransitionType::IdentityCreate, diff --git a/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs b/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs index dfb531b554..d50516c440 100644 --- a/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs +++ b/packages/rs-dpp/src/tests/fixtures/get_document_transitions_fixture.rs @@ -5,12 +5,10 @@ use platform_version::version::PlatformVersion; use std::collections::BTreeMap; use crate::document::Document; -use crate::state_transition::documents_batch_transition::document_transition::action_type::DocumentTransitionActionType; -use crate::state_transition::documents_batch_transition::document_transition::DocumentTransition; - -use crate::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; - -pub fn get_document_transitions_fixture<'a>( +use crate::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use crate::state_transition::batch_transition::batched_transition::BatchedTransition; +use crate::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionType; +pub fn get_batched_transitions_fixture<'a>( documents: impl IntoIterator< Item = ( DocumentTransitionActionType, @@ -18,7 +16,7 @@ pub fn get_document_transitions_fixture<'a>( ), >, nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, //IdentityID/ContractID -> nonce -) -> Vec { +) -> Vec { let protocol_version = PlatformVersion::latest().protocol_version; let document_factory = DocumentFactory::new(protocol_version).expect("expected to get document factory"); @@ -26,6 +24,7 @@ pub fn get_document_transitions_fixture<'a>( document_factory .create_state_transition(documents, nonce_counter) .expect("the transitions should be created") - .transitions() - .to_owned() + .transitions_iter() + .map(|batched_transition_ref| batched_transition_ref.to_owned_transition()) + .collect() } diff --git a/packages/rs-dpp/src/tokens/allowed_currency.rs b/packages/rs-dpp/src/tokens/allowed_currency.rs new file mode 100644 index 0000000000..f6c5b4da93 --- /dev/null +++ b/packages/rs-dpp/src/tokens/allowed_currency.rs @@ -0,0 +1,7 @@ +use platform_value::Identifier; + +#[derive(Debug, PartialEq, Clone)] +pub enum AllowedCurrency { + TradingInDash, + OnContract(Identifier, String), +} diff --git a/packages/rs-dpp/src/tokens/emergency_action.rs b/packages/rs-dpp/src/tokens/emergency_action.rs new file mode 100644 index 0000000000..7e18e6f426 --- /dev/null +++ b/packages/rs-dpp/src/tokens/emergency_action.rs @@ -0,0 +1,30 @@ +use crate::tokens::status::TokenStatus; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_version::version::PlatformVersion; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Copy, Default, Encode, Decode, PartialOrd, PartialEq, Eq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub enum TokenEmergencyAction { + #[default] + Pause = 0, + Resume = 1, +} + +impl TokenEmergencyAction { + pub fn resulting_status( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match self { + TokenEmergencyAction::Pause => TokenStatus::new(true, platform_version), + TokenEmergencyAction::Resume => TokenStatus::new(false, platform_version), + } + } +} diff --git a/packages/rs-dpp/src/tokens/errors.rs b/packages/rs-dpp/src/tokens/errors.rs new file mode 100644 index 0000000000..c23e619410 --- /dev/null +++ b/packages/rs-dpp/src/tokens/errors.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum TokenError { + #[error("There is no token at this position")] + TokenNotFoundAtPositionError, + #[error("The contract version does not allow tokens")] + TokenNotFoundOnContractVersion, +} diff --git a/packages/rs-dpp/src/tokens/info/methods.rs b/packages/rs-dpp/src/tokens/info/methods.rs new file mode 100644 index 0000000000..09884a8ab6 --- /dev/null +++ b/packages/rs-dpp/src/tokens/info/methods.rs @@ -0,0 +1,16 @@ +use crate::tokens::info::v0::IdentityTokenInfoV0Accessors; +use crate::tokens::info::IdentityTokenInfo; + +impl IdentityTokenInfoV0Accessors for IdentityTokenInfo { + fn frozen(&self) -> bool { + match self { + IdentityTokenInfo::V0(info) => info.frozen, + } + } + + fn set_frozen(&mut self, frozen: bool) { + match self { + IdentityTokenInfo::V0(info) => info.set_frozen(frozen), + } + } +} diff --git a/packages/rs-dpp/src/tokens/info/mod.rs b/packages/rs-dpp/src/tokens/info/mod.rs new file mode 100644 index 0000000000..ccf211d440 --- /dev/null +++ b/packages/rs-dpp/src/tokens/info/mod.rs @@ -0,0 +1,44 @@ +use crate::tokens::info::v0::IdentityTokenInfoV0; +use crate::ProtocolError; +use bincode::Encode; +use derive_more::From; +use platform_serialization::de::Decode; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_version::version::PlatformVersion; +use platform_versioning::PlatformVersioned; + +mod methods; +pub mod v0; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformVersioned, + From, + PartialEq, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum IdentityTokenInfo { + V0(IdentityTokenInfoV0), +} + +impl IdentityTokenInfo { + pub fn new(frozen: bool, platform_version: &PlatformVersion) -> Result { + match platform_version + .dpp + .token_versions + .identity_token_info_default_structure_version + { + 0 => Ok(IdentityTokenInfo::V0(IdentityTokenInfoV0 { frozen })), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "IdentityTokenInfo::new".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/tokens/info/v0/mod.rs b/packages/rs-dpp/src/tokens/info/v0/mod.rs new file mode 100644 index 0000000000..2fa6f5e310 --- /dev/null +++ b/packages/rs-dpp/src/tokens/info/v0/mod.rs @@ -0,0 +1,26 @@ +use bincode::{Decode, Encode}; +use derive_more::From; + +#[derive(Debug, Clone, Encode, Decode, From, PartialEq)] +/// Token information for an identity (version 0). +pub struct IdentityTokenInfoV0 { + pub frozen: bool, +} + +pub trait IdentityTokenInfoV0Accessors { + /// Gets the frozen state of the identity. + fn frozen(&self) -> bool; + + /// Sets the frozen state of the identity. + fn set_frozen(&mut self, frozen: bool); +} + +impl IdentityTokenInfoV0Accessors for IdentityTokenInfoV0 { + fn frozen(&self) -> bool { + self.frozen + } + + fn set_frozen(&mut self, frozen: bool) { + self.frozen = frozen; + } +} diff --git a/packages/rs-dpp/src/tokens/mod.rs b/packages/rs-dpp/src/tokens/mod.rs new file mode 100644 index 0000000000..aa8703acbf --- /dev/null +++ b/packages/rs-dpp/src/tokens/mod.rs @@ -0,0 +1,16 @@ +use crate::data_contract::TokenContractPosition; +use crate::util::hash::hash_double; + +pub mod allowed_currency; +pub mod emergency_action; +pub mod errors; +pub mod info; +pub mod status; +pub mod token_event; + +pub fn calculate_token_id(contract_id: &[u8; 32], token_pos: TokenContractPosition) -> [u8; 32] { + let mut bytes = b"dash_token".to_vec(); + bytes.extend_from_slice(contract_id); + bytes.extend_from_slice(&token_pos.to_be_bytes()); + hash_double(bytes) +} diff --git a/packages/rs-dpp/src/tokens/status/methods.rs b/packages/rs-dpp/src/tokens/status/methods.rs new file mode 100644 index 0000000000..e912ea562e --- /dev/null +++ b/packages/rs-dpp/src/tokens/status/methods.rs @@ -0,0 +1,16 @@ +use crate::tokens::status::v0::TokenStatusV0Accessors; +use crate::tokens::status::TokenStatus; + +impl TokenStatusV0Accessors for TokenStatus { + fn paused(&self) -> bool { + match self { + TokenStatus::V0(status) => status.paused, + } + } + + fn set_paused(&mut self, frozen: bool) { + match self { + TokenStatus::V0(status) => status.set_paused(frozen), + } + } +} diff --git a/packages/rs-dpp/src/tokens/status/mod.rs b/packages/rs-dpp/src/tokens/status/mod.rs new file mode 100644 index 0000000000..f39cc6be09 --- /dev/null +++ b/packages/rs-dpp/src/tokens/status/mod.rs @@ -0,0 +1,44 @@ +use crate::tokens::status::v0::TokenStatusV0; +use crate::ProtocolError; +use bincode::Encode; +use derive_more::From; +use platform_serialization::de::Decode; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_version::version::PlatformVersion; +use platform_versioning::PlatformVersioned; + +mod methods; +pub mod v0; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformVersioned, + From, + PartialEq, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum TokenStatus { + V0(TokenStatusV0), +} + +impl TokenStatus { + pub fn new(paused: bool, platform_version: &PlatformVersion) -> Result { + match platform_version + .dpp + .token_versions + .identity_token_status_default_structure_version + { + 0 => Ok(TokenStatus::V0(TokenStatusV0 { paused })), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "IdentityTokenStatus::new".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/tokens/status/v0/mod.rs b/packages/rs-dpp/src/tokens/status/v0/mod.rs new file mode 100644 index 0000000000..a8dd3a0f83 --- /dev/null +++ b/packages/rs-dpp/src/tokens/status/v0/mod.rs @@ -0,0 +1,26 @@ +use bincode::{Decode, Encode}; +use derive_more::From; + +#[derive(Debug, Clone, Encode, Decode, From, PartialEq)] +/// Token status +pub struct TokenStatusV0 { + pub paused: bool, +} + +pub trait TokenStatusV0Accessors { + /// Gets the paused state of the token. + fn paused(&self) -> bool; + + /// Sets the paused state of the token. + fn set_paused(&mut self, paused: bool); +} + +impl TokenStatusV0Accessors for TokenStatusV0 { + fn paused(&self) -> bool { + self.paused + } + + fn set_paused(&mut self, paused: bool) { + self.paused = paused; + } +} diff --git a/packages/rs-dpp/src/tokens/token_event.rs b/packages/rs-dpp/src/tokens/token_event.rs new file mode 100644 index 0000000000..df805788b1 --- /dev/null +++ b/packages/rs-dpp/src/tokens/token_event.rs @@ -0,0 +1,205 @@ +use crate::balances::credits::TokenAmount; +use crate::block::block_info::BlockInfo; +use crate::data_contract::accessors::v0::DataContractV0Getters; +use crate::data_contract::document_type::DocumentTypeRef; +use crate::document::{Document, DocumentV0}; +use crate::prelude::{ + DataContract, DerivationEncryptionKeyIndex, IdentityNonce, RecipientKeyIndex, + RootEncryptionKeyIndex, SenderKeyIndex, +}; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use platform_value::Identifier; +use std::collections::BTreeMap; + +pub type TokenEventPublicNote = Option; +pub type TokenEventSharedEncryptedNote = Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>; +pub type TokenEventPersonalEncryptedNote = Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, +)>; +use crate::tokens::emergency_action::TokenEmergencyAction; +use crate::ProtocolError; + +pub type RecipientIdentifier = Identifier; +pub type FrozenIdentifier = Identifier; + +#[derive( + Debug, PartialEq, PartialOrd, Clone, Eq, Encode, Decode, PlatformDeserialize, PlatformSerialize, +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +pub enum TokenEvent { + Mint(TokenAmount, RecipientIdentifier, TokenEventPublicNote), + Burn(TokenAmount, TokenEventPublicNote), + Freeze(FrozenIdentifier, TokenEventPublicNote), + Unfreeze(FrozenIdentifier, TokenEventPublicNote), + DestroyFrozenFunds(FrozenIdentifier, TokenAmount, TokenEventPublicNote), + Transfer( + RecipientIdentifier, + TokenEventPublicNote, + TokenEventSharedEncryptedNote, + TokenEventPersonalEncryptedNote, + TokenAmount, + ), + EmergencyAction(TokenEmergencyAction, TokenEventPublicNote), +} + +impl TokenEvent { + pub fn associated_document_type_name(&self) -> &str { + match self { + TokenEvent::Mint(_, _, _) => "mint", + TokenEvent::Burn(_, _) => "burn", + TokenEvent::Freeze(_, _) => "freeze", + TokenEvent::Unfreeze(_, _) => "unfreeze", + TokenEvent::DestroyFrozenFunds(_, _, _) => "destroyFrozenFunds", + TokenEvent::Transfer(_, _, _, _, _) => "transfer", + TokenEvent::EmergencyAction(_, _) => "emergencyAction", + } + } + + pub fn associated_document_type<'a>( + &self, + token_history_contract: &'a DataContract, + ) -> Result, ProtocolError> { + Ok(token_history_contract.document_type_for_name(self.associated_document_type_name())?) + } + + pub fn build_historical_document_owned( + self, + token_history_contract: &DataContract, + token_id: Identifier, + owner_id: Identifier, + owner_nonce: IdentityNonce, + block_info: &BlockInfo, + ) -> Result { + let document_id = Document::generate_document_id_v0( + &token_history_contract.id(), + &owner_id, + self.associated_document_type_name(), + owner_nonce.to_be_bytes().as_slice(), + ); + + let properties = match self { + TokenEvent::Mint(mint_amount, recipient_id, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("recipientId".to_string(), recipient_id.into()), + ("amount".to_string(), mint_amount.into()), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } + TokenEvent::Burn(burn_amount, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("amount".to_string(), burn_amount.into()), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } + TokenEvent::Transfer( + to, + public_note, + token_event_shared_encrypted_note, + token_event_personal_encrypted_note, + amount, + ) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("amount".to_string(), amount.into()), + ("toIdentityId".to_string(), to.into()), + ]); + if let Some(note) = public_note { + properties.insert("publicNote".to_string(), note.into()); + } + if let Some((sender_key_index, recipient_key_index, note)) = + token_event_shared_encrypted_note + { + properties.insert("encryptedSharedNote".to_string(), note.into()); + properties.insert("senderKeyIndex".to_string(), sender_key_index.into()); + properties.insert("recipientKeyIndex".to_string(), recipient_key_index.into()); + } + + if let Some((root_encryption_key_index, derivation_encryption_key_index, note)) = + token_event_personal_encrypted_note + { + properties.insert("encryptedPersonalNote".to_string(), note.into()); + properties.insert( + "rootEncryptionKeyIndex".to_string(), + root_encryption_key_index.into(), + ); + properties.insert( + "derivationEncryptionKeyIndex".to_string(), + derivation_encryption_key_index.into(), + ); + } + properties + } + TokenEvent::Freeze(frozen_identity_id, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("frozenIdentityId".to_string(), frozen_identity_id.into()), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } + TokenEvent::Unfreeze(frozen_identity_id, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("frozenIdentityId".to_string(), frozen_identity_id.into()), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } + TokenEvent::DestroyFrozenFunds(frozen_identity_id, amount, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("frozenIdentityId".to_string(), frozen_identity_id.into()), + ("amount".to_string(), amount.into()), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } + TokenEvent::EmergencyAction(action, public_note) => { + let mut properties = BTreeMap::from([ + ("tokenId".to_string(), token_id.into()), + ("action".to_string(), (action as u8).into()), + ]); + if let Some(note) = public_note { + properties.insert("note".to_string(), note.into()); + } + properties + } + }; + + let document: Document = DocumentV0 { + id: document_id, + owner_id, + properties, + revision: None, + created_at: Some(block_info.time_ms), + updated_at: None, + transferred_at: None, + created_at_block_height: Some(block_info.height), + updated_at_block_height: None, + transferred_at_block_height: None, + created_at_core_block_height: None, + updated_at_core_block_height: None, + transferred_at_core_block_height: None, + } + .into(); + + Ok(document) + } +} diff --git a/packages/rs-dpp/src/validation/meta_validators/mod.rs b/packages/rs-dpp/src/validation/meta_validators/mod.rs index 8d1ce93b7e..05e1024a52 100644 --- a/packages/rs-dpp/src/validation/meta_validators/mod.rs +++ b/packages/rs-dpp/src/validation/meta_validators/mod.rs @@ -36,10 +36,14 @@ lazy_static! { "../../../schema/meta_schemas/draft2020-12/meta/content.json" )) .expect("Valid schema!"); - static ref DATA_CONTRACT_V0: Value = serde_json::from_str::(include_str!( + static ref DOCUMENT_META_JSON_V0: Value = serde_json::from_str::(include_str!( "../../../schema/meta_schemas/document/v0/document-meta.json" )) .unwrap(); + static ref TOKEN_META_JSON_V0: Value = serde_json::from_str::(include_str!( + "../../../schema/meta_schemas/token/v0/token-meta.json" + )) + .unwrap(); pub static ref DRAFT_202012_META_SCHEMA: JSONSchema = JSONSchema::options() .with_draft(Draft::Draft202012) @@ -85,8 +89,7 @@ lazy_static! { .compile(&DRAFT202012) .expect("Invalid data contract schema"); - - // Compiled version of data contract meta schema + // Compiled version of document meta schema pub static ref DOCUMENT_META_SCHEMA_V0: JSONSchema = JSONSchema::options() .with_keyword( "byteArray", @@ -137,6 +140,60 @@ lazy_static! { DRAFT202012.clone(), ) .to_owned() - .compile(&DATA_CONTRACT_V0) + .compile(&DOCUMENT_META_JSON_V0) + .expect("Invalid data contract schema"); + + // Compiled version of token meta schema + pub static ref TOKEN_META_SCHEMA_V0: JSONSchema = JSONSchema::options() + .with_keyword( + "byteArray", + |_, _, _| Ok(Box::new(ByteArrayKeyword)), + ) + .with_patterns_regex_engine(RegexEngine::Regex(RegexOptions { + size_limit: Some(5 * (1 << 20)), + ..Default::default() + })) + .should_ignore_unknown_formats(false) + .should_validate_formats(true) + .with_patterns_regex_engine(RegexEngine::Regex(Default::default())) + .with_draft(Draft::Draft202012) + .with_document( + "https://json-schema.org/draft/2020-12/meta/applicator".to_string(), + DRAFT202012_APPLICATOR.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/core".to_string(), + DRAFT202012_CORE.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/applicator".to_string(), + DRAFT202012_APPLICATOR.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/unevaluated".to_string(), + DRAFT202012_UNEVALUATED.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/validation".to_string(), + DRAFT202012_VALIDATION.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/meta-data".to_string(), + DRAFT202012_META_DATA.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/format-annotation".to_string(), + DRAFT202012_FORMAT_ANNOTATION.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/meta/content".to_string(), + DRAFT202012_CONTENT.clone(), + ) + .with_document( + "https://json-schema.org/draft/2020-12/schema".to_string(), + DRAFT202012.clone(), + ) + .to_owned() + .compile(&TOKEN_META_JSON_V0) .expect("Invalid data contract schema"); } diff --git a/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs b/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs index 7ff0929f61..ed4c0fc079 100644 --- a/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs +++ b/packages/rs-dpp/src/voting/contender_structs/contender/v0/mod.rs @@ -1,8 +1,8 @@ use crate::data_contract::document_type::DocumentTypeRef; use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0; use crate::document::Document; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_value::Identifier; use platform_version::version::PlatformVersion; diff --git a/packages/rs-dpp/src/voting/contender_structs/mod.rs b/packages/rs-dpp/src/voting/contender_structs/mod.rs index 0e8d96c25f..a71c77f19a 100644 --- a/packages/rs-dpp/src/voting/contender_structs/mod.rs +++ b/packages/rs-dpp/src/voting/contender_structs/mod.rs @@ -3,9 +3,9 @@ mod contender; use crate::data_contract::document_type::DocumentTypeRef; use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0; use crate::document::Document; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_value::Identifier; use platform_version::version::PlatformVersion; use std::fmt; diff --git a/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs b/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs index 12eb2b400c..90a920fa78 100644 --- a/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs +++ b/packages/rs-dpp/src/voting/vote_info_storage/contested_document_vote_poll_stored_info/mod.rs @@ -1,13 +1,13 @@ mod v0; use crate::block::block_info::BlockInfo; -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::contender_structs::{ ContenderWithSerializedDocument, FinalizedResourceVoteChoicesWithVoterInfo, }; use crate::voting::vote_info_storage::contested_document_vote_poll_stored_info::v0::ContestedDocumentVotePollStoredInfoV0; use crate::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo; use crate::ProtocolError; +use bincode::{Decode, Encode}; use derive_more::From; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; diff --git a/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs b/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs index 21f953f844..9342eae819 100644 --- a/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs +++ b/packages/rs-dpp/src/voting/vote_polls/contested_document_resource_vote_poll/mod.rs @@ -1,7 +1,7 @@ -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::serialization::PlatformSerializable; use crate::util::hash::hash_double; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::{Identifier, Value}; #[cfg(feature = "vote-serde-conversion")] diff --git a/packages/rs-dpp/src/voting/vote_polls/mod.rs b/packages/rs-dpp/src/voting/vote_polls/mod.rs index 9186451e68..938a852ed4 100644 --- a/packages/rs-dpp/src/voting/vote_polls/mod.rs +++ b/packages/rs-dpp/src/voting/vote_polls/mod.rs @@ -1,6 +1,6 @@ -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; use crate::ProtocolError; +use bincode::{Decode, Encode}; use derive_more::From; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use platform_value::Identifier; diff --git a/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs b/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs index 8ee89fe371..15787e88d7 100644 --- a/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs +++ b/packages/rs-dpp/src/voting/votes/resource_vote/mod.rs @@ -1,6 +1,6 @@ -use crate::identity::state_transition::asset_lock_proof::{Decode, Encode}; use crate::voting::votes::resource_vote::v0::ResourceVoteV0; use crate::ProtocolError; +use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; #[cfg(feature = "vote-serde-conversion")] use serde::{Deserialize, Serialize}; diff --git a/packages/rs-drive-abci/src/config.rs b/packages/rs-drive-abci/src/config.rs index 1e8f5f3c26..afa20e34f5 100644 --- a/packages/rs-drive-abci/src/config.rs +++ b/packages/rs-drive-abci/src/config.rs @@ -105,6 +105,10 @@ pub struct ExecutionConfig { #[serde(default = "ExecutionConfig::default_verify_sum_trees")] pub verify_sum_trees: bool, + /// Should we verify sum trees? Useful to set as `false` for tests + #[serde(default = "ExecutionConfig::default_verify_token_sum_trees")] + pub verify_token_sum_trees: bool, + /// How long in seconds should an epoch last /// It might last a lot longer if the chain is halted #[serde( @@ -614,6 +618,10 @@ impl ExecutionConfig { true } + fn default_verify_token_sum_trees() -> bool { + true + } + fn default_use_document_triggers() -> bool { true } @@ -669,6 +677,7 @@ impl Default for ExecutionConfig { Self { use_document_triggers: ExecutionConfig::default_use_document_triggers(), verify_sum_trees: ExecutionConfig::default_verify_sum_trees(), + verify_token_sum_trees: ExecutionConfig::default_verify_token_sum_trees(), epoch_time_length_s: ExecutionConfig::default_epoch_time_length_s(), } } diff --git a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs index acfb7fca04..06292c2342 100644 --- a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs @@ -229,8 +229,8 @@ mod tests { use dpp::serialization::{PlatformSerializable, Signable}; use dpp::native_bls::NativeBlsModule; - use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; - use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; + use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; + use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::identity_create_transition::methods::IdentityCreateTransitionMethodsV0; use dpp::state_transition::identity_create_transition::IdentityCreateTransition; use dpp::state_transition::identity_topup_transition::methods::IdentityTopUpTransitionMethodsV0; @@ -381,7 +381,7 @@ mod tests { } #[test] - fn data_contract_create_check_tx() { + fn data_contract_create_check_tx_first_protocol_version() { let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -392,6 +392,7 @@ mod tests { let platform = TestPlatformBuilder::new() .with_config(platform_config) + .with_initial_protocol_version(1) .build_with_mock_rpc(); let platform_state = platform.state.load(); @@ -523,6 +524,149 @@ mod tests { )); } + #[test] + fn data_contract_create_check_tx_latest_protocol_version() { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); + + let platform_state = platform.state.load(); + let protocol_version = platform_state.current_protocol_version_in_consensus(); + let platform_version = PlatformVersion::get(protocol_version).unwrap(); + + let (key, private_key) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(1), + platform_version, + ) + .expect("expected to get key pair"); + + platform + .drive + .create_initial_state_structure(None, platform_version) + .expect("expected to create state structure"); + let identity: Identity = IdentityV0 { + id: Identifier::new([ + 158, 113, 180, 126, 91, 83, 62, 44, 83, 54, 97, 88, 240, 215, 84, 139, 167, 156, + 166, 203, 222, 4, 64, 31, 215, 199, 149, 151, 190, 246, 251, 44, + ]), + public_keys: BTreeMap::from([(1, key.clone())]), + balance: 1000000000, + revision: 0, + } + .into(); + + let dashpay = get_dashpay_contract_fixture(Some(identity.id()), 1, protocol_version); + let mut create_contract_state_transition: StateTransition = dashpay + .try_into_platform_versioned(platform_version) + .expect("expected a state transition"); + create_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized = create_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + platform + .drive + .add_new_identity( + identity, + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert identity"); + + let platform_ref = PlatformRef { + drive: &platform.drive, + state: &platform_state, + config: &platform.config, + core_rpc: &platform.core_rpc, + }; + + let validation_result = platform + .check_tx( + serialized.as_slice(), + FirstTimeCheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(validation_result.errors.is_empty()); + + let check_result = platform + .check_tx( + serialized.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2484410); + + let check_result = platform + .check_tx( + serialized.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); // it should still be valid, because we didn't commit the transaction + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let check_result = platform + .check_tx( + serialized.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(!check_result.is_valid()); // it should no longer be valid, because of the nonce check + + assert!(matches!( + check_result.errors.first().expect("expected an error"), + ConsensusError::StateError(StateError::InvalidIdentityNonceError(_)) + )); + } + #[test] fn data_contract_create_check_tx_for_invalid_contract() { let platform_config = PlatformConfig { @@ -728,7 +872,7 @@ mod tests { } #[test] - fn data_contract_create_check_tx_priority() { + fn data_contract_create_check_tx_priority_first_protocol_version() { let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -739,6 +883,7 @@ mod tests { let platform = TestPlatformBuilder::new() .with_config(platform_config) + .with_initial_protocol_version(1) .build_with_mock_rpc(); let platform_state = platform.state.load(); @@ -882,7 +1027,7 @@ mod tests { } #[test] - fn data_contract_create_check_tx_after_identity_balance_used_up() { + fn data_contract_create_check_tx_priority_latest_protocol_version() { let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -923,7 +1068,7 @@ mod tests { 166, 203, 222, 4, 64, 31, 215, 199, 149, 151, 190, 246, 251, 44, ]), public_keys: BTreeMap::from([(1, key.clone())]), - balance: 200000000, // we have enough balance only for 1 insertion (this is where this test is different) + balance: 1000000000, revision: 0, } .into(); @@ -932,6 +1077,9 @@ mod tests { let mut create_contract_state_transition: StateTransition = dashpay .try_into_platform_versioned(platform_version) .expect("expected a state transition"); + + create_contract_state_transition.set_user_fee_increase(100); // This means that things will be twice as expensive + create_contract_state_transition .sign(&key, private_key.as_slice(), &NativeBlsModule) .expect("expected to sign transition"); @@ -961,6 +1109,8 @@ mod tests { assert!(validation_result.errors.is_empty()); + assert_eq!(validation_result.data.unwrap().priority, 10000); + let check_result = platform .check_tx( serialized.as_slice(), @@ -972,9 +1122,11 @@ mod tests { assert!(check_result.is_valid()); + assert_eq!(check_result.data.unwrap().priority, 10000); + let transaction = platform.drive.grove.start_transaction(); - platform + let processing_result = platform .platform .process_raw_state_transitions( &vec![serialized.clone()], @@ -987,6 +1139,10 @@ mod tests { ) .expect("expected to process state transition"); + // The processing fees should be twice as much as a fee multiplier of 0, + // since a fee multiplier of 100 means 100% more of 1 (gives 2) + assert_eq!(processing_result.aggregated_fees().processing_fee, 4968820); + let check_result = platform .check_tx( serialized.as_slice(), @@ -998,6 +1154,8 @@ mod tests { assert!(check_result.is_valid()); // it should still be valid, because we didn't commit the transaction + assert_eq!(check_result.data.unwrap().priority, 10000); + platform .drive .grove @@ -1014,11 +1172,16 @@ mod tests { ) .expect("expected to check tx"); - assert!(!check_result.is_valid()); // the identity shouldn't have enough balance anymore + assert!(!check_result.is_valid()); // it should no longer be valid, because of the nonce check + + assert!(matches!( + check_result.errors.first().expect("expected an error"), + ConsensusError::StateError(StateError::InvalidIdentityNonceError(_)) + )); } #[test] - fn data_contract_update_check_tx() { + fn data_contract_create_check_tx_after_identity_balance_used_up() { let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -1059,15 +1222,13 @@ mod tests { 166, 203, 222, 4, 64, 31, 215, 199, 149, 151, 190, 246, 251, 44, ]), public_keys: BTreeMap::from([(1, key.clone())]), - balance: 1000000000, + balance: 200000000, // we have enough balance only for 1 insertion (this is where this test is different) revision: 0, } .into(); - let dashpay_created_contract = - get_dashpay_contract_fixture(Some(identity.id()), 1, protocol_version); - let mut modified_dashpay_contract = dashpay_created_contract.data_contract().clone(); - let mut create_contract_state_transition: StateTransition = dashpay_created_contract + let dashpay = get_dashpay_contract_fixture(Some(identity.id()), 1, protocol_version); + let mut create_contract_state_transition: StateTransition = dashpay .try_into_platform_versioned(platform_version) .expect("expected a state transition"); create_contract_state_transition @@ -1079,7 +1240,7 @@ mod tests { platform .drive .add_new_identity( - identity.clone(), + identity, false, &BlockInfo::default(), true, @@ -1088,68 +1249,9 @@ mod tests { ) .expect("expected to insert identity"); - let transaction = platform.drive.grove.start_transaction(); - - let processing_result = platform - .platform - .process_raw_state_transitions( - &vec![serialized.clone()], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - false, - None, - ) - .expect("expected to process state transition"); - - assert_eq!(processing_result.aggregated_fees().processing_fee, 2483610); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("expected to commit"); - - // Now let's do the data contract update - let _dashpay_id = modified_dashpay_contract.id(); - // we need to alter dashpay to make it invalid - - modified_dashpay_contract.set_version(2); - - let document_types = modified_dashpay_contract.document_types_mut(); - - let dpns_contract = - get_dpns_data_contract_fixture(Some(identity.id()), 1, protocol_version) - .data_contract_owned(); - - document_types.insert( - "preorder".to_string(), - dpns_contract - .document_type_for_name("preorder") - .expect("expected document type") - .to_owned_document_type(), - ); - - let mut update_contract_state_transition: StateTransition = - DataContractUpdateTransition::try_from_platform_versioned( - (modified_dashpay_contract, 2), - platform_version, - ) - .expect("expected a state transition") - .into(); - - update_contract_state_transition - .sign(&key, private_key.as_slice(), &NativeBlsModule) - .expect("expected to sign transition"); - let serialized_update = update_contract_state_transition - .serialize_to_bytes() - .expect("serialized state transition"); - let validation_result = platform .check_tx( - serialized_update.as_slice(), + serialized.as_slice(), FirstTimeCheck, &platform_ref, platform_version, @@ -1160,7 +1262,7 @@ mod tests { let check_result = platform .check_tx( - serialized_update.as_slice(), + serialized.as_slice(), Recheck, &platform_ref, platform_version, @@ -1171,10 +1273,10 @@ mod tests { let transaction = platform.drive.grove.start_transaction(); - let update_processing_result = platform + platform .platform .process_raw_state_transitions( - &vec![serialized_update.clone()], + &vec![serialized.clone()], &platform_state, &BlockInfo::default(), &transaction, @@ -1184,17 +1286,9 @@ mod tests { ) .expect("expected to process state transition"); - // We have one invalid paid for state transition - assert_eq!(update_processing_result.valid_count(), 1); - - assert_eq!( - update_processing_result.aggregated_fees().processing_fee, - 2495990 - ); - let check_result = platform .check_tx( - serialized_update.as_slice(), + serialized.as_slice(), Recheck, &platform_ref, platform_version, @@ -1212,14 +1306,430 @@ mod tests { let check_result = platform .check_tx( - serialized_update.as_slice(), + serialized.as_slice(), Recheck, &platform_ref, platform_version, ) .expect("expected to check tx"); - assert!(!check_result.is_valid()); // it should no longer be valid, because of the nonce check + assert!(!check_result.is_valid()); // the identity shouldn't have enough balance anymore + } + + #[test] + fn data_contract_update_check_tx_first_protocol_version() { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .with_initial_protocol_version(1) + .build_with_mock_rpc(); + + let platform_state = platform.state.load(); + let protocol_version = platform_state.current_protocol_version_in_consensus(); + let platform_version = PlatformVersion::get(protocol_version).unwrap(); + + let platform_ref = PlatformRef { + drive: &platform.drive, + state: &platform_state, + config: &platform.config, + core_rpc: &platform.core_rpc, + }; + + let (key, private_key) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(1), + platform_version, + ) + .expect("expected to get key pair"); + + platform + .drive + .create_initial_state_structure(None, platform_version) + .expect("expected to create state structure"); + let identity: Identity = IdentityV0 { + id: Identifier::new([ + 158, 113, 180, 126, 91, 83, 62, 44, 83, 54, 97, 88, 240, 215, 84, 139, 167, 156, + 166, 203, 222, 4, 64, 31, 215, 199, 149, 151, 190, 246, 251, 44, + ]), + public_keys: BTreeMap::from([(1, key.clone())]), + balance: 1000000000, + revision: 0, + } + .into(); + + let dashpay_created_contract = + get_dashpay_contract_fixture(Some(identity.id()), 1, protocol_version); + let mut modified_dashpay_contract = dashpay_created_contract.data_contract().clone(); + let mut create_contract_state_transition: StateTransition = dashpay_created_contract + .try_into_platform_versioned(platform_version) + .expect("expected a state transition"); + create_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized = create_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + platform + .drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert identity"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2483610); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // Now let's do the data contract update + let _dashpay_id = modified_dashpay_contract.id(); + // we need to alter dashpay to make it invalid + + modified_dashpay_contract.set_version(2); + + let document_types = modified_dashpay_contract.document_types_mut(); + + let dpns_contract = + get_dpns_data_contract_fixture(Some(identity.id()), 1, protocol_version) + .data_contract_owned(); + + document_types.insert( + "preorder".to_string(), + dpns_contract + .document_type_for_name("preorder") + .expect("expected document type") + .to_owned_document_type(), + ); + + let mut update_contract_state_transition: StateTransition = + DataContractUpdateTransition::try_from_platform_versioned( + (modified_dashpay_contract, 2), + platform_version, + ) + .expect("expected a state transition") + .into(); + + update_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized_update = update_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let validation_result = platform + .check_tx( + serialized_update.as_slice(), + FirstTimeCheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(validation_result.errors.is_empty()); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); + + let transaction = platform.drive.grove.start_transaction(); + + let update_processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized_update.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + // We have one invalid paid for state transition + assert_eq!(update_processing_result.valid_count(), 1); + + assert_eq!( + update_processing_result.aggregated_fees().processing_fee, + 2495990 + ); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); // it should still be valid, because we didn't commit the transaction + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(!check_result.is_valid()); // it should no longer be valid, because of the nonce check + + assert!(matches!( + check_result.errors.first().expect("expected an error"), + ConsensusError::StateError(StateError::InvalidIdentityNonceError(_)) + )); + } + + #[test] + fn data_contract_update_check_tx_latest_protocol_version() { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); + + let platform_state = platform.state.load(); + let protocol_version = platform_state.current_protocol_version_in_consensus(); + let platform_version = PlatformVersion::get(protocol_version).unwrap(); + + let platform_ref = PlatformRef { + drive: &platform.drive, + state: &platform_state, + config: &platform.config, + core_rpc: &platform.core_rpc, + }; + + let (key, private_key) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(1), + platform_version, + ) + .expect("expected to get key pair"); + + platform + .drive + .create_initial_state_structure(None, platform_version) + .expect("expected to create state structure"); + let identity: Identity = IdentityV0 { + id: Identifier::new([ + 158, 113, 180, 126, 91, 83, 62, 44, 83, 54, 97, 88, 240, 215, 84, 139, 167, 156, + 166, 203, 222, 4, 64, 31, 215, 199, 149, 151, 190, 246, 251, 44, + ]), + public_keys: BTreeMap::from([(1, key.clone())]), + balance: 1000000000, + revision: 0, + } + .into(); + + let dashpay_created_contract = + get_dashpay_contract_fixture(Some(identity.id()), 1, protocol_version); + let mut modified_dashpay_contract = dashpay_created_contract.data_contract().clone(); + let mut create_contract_state_transition: StateTransition = dashpay_created_contract + .try_into_platform_versioned(platform_version) + .expect("expected a state transition"); + create_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized = create_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + platform + .drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert identity"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2484410); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // Now let's do the data contract update + let _dashpay_id = modified_dashpay_contract.id(); + // we need to alter dashpay to make it invalid + + modified_dashpay_contract.set_version(2); + + let document_types = modified_dashpay_contract.document_types_mut(); + + let dpns_contract = + get_dpns_data_contract_fixture(Some(identity.id()), 1, protocol_version) + .data_contract_owned(); + + document_types.insert( + "preorder".to_string(), + dpns_contract + .document_type_for_name("preorder") + .expect("expected document type") + .to_owned_document_type(), + ); + + let mut update_contract_state_transition: StateTransition = + DataContractUpdateTransition::try_from_platform_versioned( + (modified_dashpay_contract, 2), + platform_version, + ) + .expect("expected a state transition") + .into(); + + update_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized_update = update_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let validation_result = platform + .check_tx( + serialized_update.as_slice(), + FirstTimeCheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(validation_result.errors.is_empty()); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); + + let transaction = platform.drive.grove.start_transaction(); + + let update_processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized_update.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + // We have one invalid paid for state transition + assert_eq!(update_processing_result.valid_count(), 1); + + assert_eq!( + update_processing_result.aggregated_fees().processing_fee, + 2496910 + ); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); // it should still be valid, because we didn't commit the transaction + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(!check_result.is_valid()); // it should no longer be valid, because of the nonce check assert!(matches!( check_result.errors.first().expect("expected an error"), @@ -1228,7 +1738,7 @@ mod tests { } #[test] - fn data_contract_update_check_tx_for_invalid_update() { + fn data_contract_update_check_tx_for_invalid_update_first_protocol_version() { let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -1239,6 +1749,7 @@ mod tests { let platform = TestPlatformBuilder::new() .with_config(platform_config) + .with_initial_protocol_version(1) .build_with_mock_rpc(); let platform_state = platform.state.load(); @@ -1472,6 +1983,251 @@ mod tests { )); } + #[test] + fn data_contract_update_check_tx_for_invalid_update_latest_protocol_version() { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); + + let platform_state = platform.state.load(); + let protocol_version = platform_state.current_protocol_version_in_consensus(); + let platform_version = PlatformVersion::get(protocol_version).unwrap(); + + let platform_ref = PlatformRef { + drive: &platform.drive, + state: &platform_state, + config: &platform.config, + core_rpc: &platform.core_rpc, + }; + + let (key, private_key) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(1), + platform_version, + ) + .expect("expected to get key pair"); + + platform + .drive + .create_initial_state_structure(None, platform_version) + .expect("expected to create state structure"); + let identity: Identity = IdentityV0 { + id: Identifier::new([ + 158, 113, 180, 126, 91, 83, 62, 44, 83, 54, 97, 88, 240, 215, 84, 139, 167, 156, + 166, 203, 222, 4, 64, 31, 215, 199, 149, 151, 190, 246, 251, 44, + ]), + public_keys: BTreeMap::from([(1, key.clone())]), + balance: 1000000000, + revision: 0, + } + .into(); + + let dashpay_created_contract = + get_dashpay_contract_fixture(Some(identity.id()), 1, protocol_version); + let mut modified_dashpay_contract = dashpay_created_contract.data_contract().clone(); + let mut create_contract_state_transition: StateTransition = dashpay_created_contract + .try_into_platform_versioned(platform_version) + .expect("expected a state transition"); + create_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized = create_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + platform + .drive + .add_new_identity( + identity, + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert identity"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2484410); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // Now let's do the data contract update + let dashpay_id = modified_dashpay_contract.id(); + // we need to alter dashpay to make it invalid + + let document_types = modified_dashpay_contract.document_types_mut(); + + let parameters = RandomDocumentTypeParameters { + new_fields_optional_count_range: 5..6, + new_fields_required_count_range: 3..4, + new_indexes_count_range: Default::default(), + field_weights: FieldTypeWeights { + string_weight: 5, + float_weight: 3, + integer_weight: 2, + date_weight: 0, + boolean_weight: 1, + byte_array_weight: 0, + }, + field_bounds: FieldMinMaxBounds { + string_min_len: Default::default(), + string_has_min_len_chance: 0.0, + string_max_len: Default::default(), + string_has_max_len_chance: 0.0, + integer_min: Default::default(), + integer_has_min_chance: 0.0, + integer_max: Default::default(), + integer_has_max_chance: 0.0, + float_min: Default::default(), + float_has_min_chance: 0.0, + float_max: Default::default(), + float_has_max_chance: 0.0, + date_min: 0, + date_max: 100, + byte_array_min_len: Default::default(), + byte_array_has_min_len_chance: 0.0, + byte_array_max_len: Default::default(), + byte_array_has_max_len_chance: 0.0, + }, + keep_history_chance: 0.0, + documents_mutable_chance: 0.0, + documents_can_be_deleted_chance: 0.0, + }; + + let mut rng = StdRng::seed_from_u64(6); + + document_types.insert( + "invalid".to_string(), + DocumentType::V0( + DocumentTypeV0::invalid_random_document_type( + parameters, + dashpay_id, + &mut rng, + platform_version, + ) + .expect("expected an invalid document type"), + ), + ); + + let mut update_contract_state_transition: StateTransition = + DataContractUpdateTransition::try_from_platform_versioned( + (modified_dashpay_contract, 2), + platform_version, + ) + .expect("expected a state transition") + .into(); + + update_contract_state_transition + .sign(&key, private_key.as_slice(), &NativeBlsModule) + .expect("expected to sign transition"); + let serialized_update = update_contract_state_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let validation_result = platform + .check_tx( + serialized_update.as_slice(), + FirstTimeCheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(validation_result.errors.is_empty()); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![serialized_update.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + // We have one invalid paid for state transition + assert_eq!(processing_result.invalid_paid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 448640); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(check_result.is_valid()); // it should still be valid, because we didn't commit the transaction + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let check_result = platform + .check_tx( + serialized_update.as_slice(), + Recheck, + &platform_ref, + platform_version, + ) + .expect("expected to check tx"); + + assert!(!check_result.is_valid()); // it should no longer be valid, because of the nonce check + + assert!(matches!( + check_result.errors.first().expect("expected an error"), + ConsensusError::StateError(StateError::InvalidIdentityNonceError(_)) + )); + } + #[test] fn document_update_check_tx() { let platform_config = PlatformConfig { @@ -1592,7 +2348,7 @@ mod tests { altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -1612,7 +2368,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, diff --git a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v0/mod.rs index 6eb4fd82bb..67590faa83 100644 --- a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v0/mod.rs @@ -368,7 +368,7 @@ where let block_fees_v0: BlockFeesV0 = state_transitions_result.aggregated_fees().clone().into(); // Process fees - let processed_block_fees = self.process_block_fees( + let processed_block_fees = self.process_block_fees_and_validate_sum_trees( &block_execution_context, block_fees_v0.into(), transaction, diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/add_process_epoch_change_operations/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/add_process_epoch_change_operations/mod.rs diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/add_process_epoch_change_operations/v0/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/v0/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/add_process_epoch_change_operations/v0/mod.rs diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs similarity index 56% rename from packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs index 232c76143e..03c783e1dd 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs @@ -1,5 +1,5 @@ mod add_process_epoch_change_operations; -pub mod process_block_fees; +pub mod process_block_fees_and_validate_sum_trees; #[cfg(test)] mod tests; diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/mod.rs similarity index 79% rename from packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/mod.rs index 7ab4cbe08d..012bc0528b 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use dpp::version::PlatformVersion; @@ -34,7 +35,7 @@ impl Platform { /// * `Result` - /// If the operation is successful, it returns `Ok(ProcessedBlockFeesOutcome)`. If there is an error, it returns `Error`. /// - pub fn process_block_fees( + pub fn process_block_fees_and_validate_sum_trees( &self, block_execution_context: &BlockExecutionContext, block_fees: BlockFees, @@ -45,17 +46,23 @@ impl Platform { .drive_abci .methods .block_fee_processing - .process_block_fees + .process_block_fees_and_validate_sum_trees { - 0 => self.process_block_fees_v0( + 0 => self.process_block_fees_and_validate_sum_trees_v0( + block_execution_context, + block_fees, + transaction, + platform_version, + ), + 1 => self.process_block_fees_and_validate_sum_trees_v1( block_execution_context, block_fees, transaction, platform_version, ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { - method: "process_block_fees".to_string(), - known_versions: vec![0], + method: "process_block_fees_and_validate_sum_trees".to_string(), + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v0/mod.rs similarity index 99% rename from packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs rename to packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v0/mod.rs index 4bb341a678..a3fa671956 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v0/mod.rs @@ -47,7 +47,7 @@ impl Platform { /// /// Returns `ProcessedBlockFeesOutcome`. #[inline(always)] - pub(super) fn process_block_fees_v0( + pub(super) fn process_block_fees_and_validate_sum_trees_v0( &self, block_execution_context: &BlockExecutionContext, block_fees: BlockFees, @@ -274,7 +274,7 @@ mod tests { }; let storage_fee_distribution_outcome = platform - .process_block_fees_v0( + .process_block_fees_and_validate_sum_trees_v0( &block_execution_context.into(), block_fees.clone(), transaction, diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v1/mod.rs new file mode 100644 index 0000000000..4e9edf37f2 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/process_block_fees_and_validate_sum_trees/v1/mod.rs @@ -0,0 +1,54 @@ +//! Block Fees Processing. +//! +//! This module defines functions related to processing block fees upon block and +//! epoch changes. +//! + +use crate::error::Error; +use crate::execution::types::block_execution_context::BlockExecutionContext; +use crate::execution::types::block_fees::BlockFees; +use crate::execution::types::processed_block_fees_outcome; +use crate::platform_types::platform::Platform; +use dpp::version::PlatformVersion; +use drive::grovedb::Transaction; + +/// From the Dash Improvement Proposal: + +/// For the purpose of this explanation we can trivialize that the execution of a block comprises +/// the sum of the execution of all state transitions contained within the block. In order to +/// avoid altering participating masternode identity balances every block and distribute fees +/// evenly, the concept of pools is introduced. We will also introduce the concepts of an Epoch +/// and the Epoch Era that are both covered later in this document. As the block executes state +/// transitions, processing and storage fees are accumulated, as well as a list of refunded fees +/// from various Epochs and fee multipliers. When there are no more state transitions to execute +/// we can say the block has ended its state transition execution phase. The system will then add +/// the accumulated fees to their corresponding pools, and in the case of deletion of data, remove +/// storage fees from future Epoch storage pools. + +impl Platform { + /// Adds operations to GroveDB op batch related to processing + /// and distributing the block fees from the previous block and applies the batch. + /// + /// Returns `ProcessedBlockFeesOutcome`. + /// + /// V1 adds the validation of the token aggregated balance + #[inline(always)] + pub(super) fn process_block_fees_and_validate_sum_trees_v1( + &self, + block_execution_context: &BlockExecutionContext, + block_fees: BlockFees, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result { + let outcome = self.process_block_fees_and_validate_sum_trees_v0( + block_execution_context, + block_fees, + transaction, + platform_version, + )?; + + self.validate_token_aggregated_balance(transaction, platform_version)?; + + Ok(outcome) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs similarity index 95% rename from packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs rename to packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs index 1cbac74c74..2c0fe0a027 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/tests.rs @@ -16,6 +16,7 @@ mod refund_tests { CreateRandomDocument, DocumentFieldFillSize, DocumentFieldFillType, }; use dpp::data_contract::document_type::DocumentTypeRef; + use dpp::data_contract::DataContract; use dpp::document::document_methods::DocumentMethodsV0; use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; use dpp::document::{Document, DocumentV0Setters}; @@ -24,8 +25,8 @@ mod refund_tests { use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::{Identity, IdentityPublicKey}; use dpp::platform_value::Bytes32; - use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; - use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; + use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; + use dpp::state_transition::batch_transition::BatchTransition; use drive::util::test_helpers::setup_contract; use platform_version::version::PlatformVersion; use rand::prelude::StdRng; @@ -71,7 +72,7 @@ mod refund_tests { altered_document.set("avatarUrl", "http://test.com/dog.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), profile, entropy.0, @@ -178,7 +179,7 @@ mod refund_tests { assert_eq!(serialized_len, 173); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), profile, entropy.0, @@ -272,6 +273,9 @@ mod refund_tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-indexes.json", None, None, + None::, + None, + None, ); let profile = dashpay_contract_no_indexes @@ -296,7 +300,7 @@ mod refund_tests { setup_initial_document(&platform, profile, &mut rng, &identity, &key, &signer); let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, profile, &key, @@ -368,6 +372,9 @@ mod refund_tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-indexes.json", None, None, + None::, + None, + None, ); let profile = dashpay_contract_no_indexes @@ -392,7 +399,7 @@ mod refund_tests { fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 1, false); //next epoch let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, profile, &key, @@ -467,6 +474,9 @@ mod refund_tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-indexes.json", None, None, + None::, + None, + None, ); let profile = dashpay_contract_no_indexes @@ -491,7 +501,7 @@ mod refund_tests { fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 40, false); //a year later let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, profile, &key, @@ -562,6 +572,9 @@ mod refund_tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-indexes.json", None, None, + None::, + None, + None, ); let profile = dashpay_contract_no_indexes @@ -586,7 +599,7 @@ mod refund_tests { fast_forward_to_block(&platform, 10_200_000_000, 9000, 42, 40 * 25, false); //25 years later let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, profile, &key, @@ -657,6 +670,9 @@ mod refund_tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-indexes.json", None, None, + None::, + None, + None, ); let profile = dashpay_contract_no_indexes @@ -681,7 +697,7 @@ mod refund_tests { fast_forward_to_block(&platform, 10_200_000_000, 9000, 42, 40 * 50, false); //50 years later let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, profile, &key, @@ -753,6 +769,9 @@ mod refund_tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-indexes.json", None, None, + None::, + None, + None, ); let profile = dashpay_contract_no_indexes @@ -777,7 +796,7 @@ mod refund_tests { fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 10, false); //next epoch let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, profile, &key, @@ -823,9 +842,6 @@ mod refund_tests { .calculate_refunds_amount_for_identity(identity.id()) .expect("expected refunds for identity"); - // println!("{}", insertion_fee_result.storage_fee); - // println!("{}", refund_amount); - // we should be refunding around 21% after 25 years. let refunded_percentage = refund_amount * 100 / insertion_fee_result.storage_fee; assert_eq!(refunded_percentage, 98); diff --git a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/common.rs b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/common.rs new file mode 100644 index 0000000000..9d0a27dec4 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/common.rs @@ -0,0 +1,101 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; + +use dpp::platform_value::platform_value; +use dpp::ProtocolError; + +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::DataContract; +use dpp::document::DocumentV0; +use dpp::serialization::PlatformSerializableWithPlatformVersion; +use dpp::system_data_contracts::dpns_contract::DPNS_DASH_TLD_DOCUMENT_ID; +use dpp::version::PlatformVersion; +use drive::dpp::identity::TimestampMillis; +use drive::util::batch::{DataContractOperationType, DocumentOperationType, DriveOperation}; +use drive::util::object_size_info::{ + DataContractInfo, DocumentInfo, DocumentTypeInfo, OwnedDocumentInfo, +}; +use std::borrow::Cow; + +impl Platform { + pub(in crate::execution::platform_events::initialization::create_genesis_state) fn register_system_data_contract_operations< + 'a, + >( + &self, + data_contract: &'a DataContract, + operations: &mut Vec>, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let serialization = + data_contract.serialize_to_bytes_with_platform_version(platform_version)?; + operations.push(DriveOperation::DataContractOperation( + DataContractOperationType::ApplyContractWithSerialization { + contract: Cow::Borrowed(data_contract), + serialized_contract: serialization, + storage_flags: None, + }, + )); + Ok(()) + } + + pub(in crate::execution::platform_events::initialization::create_genesis_state) fn register_dpns_top_level_domain_operations< + 'a, + >( + &'a self, + contract: &'a DataContract, + genesis_time: TimestampMillis, + operations: &mut Vec>, + ) -> Result<(), Error> { + let domain = "dash"; + + let document_stub_properties_value = platform_value!({ + "label" : domain, + "normalizedLabel" : domain, + "parentDomainName" : "", + "normalizedParentDomainName" : "", + "records" : { + "identity" : contract.owner_id(), + }, + "subdomainRules": { + "allowSubdomains": true, + } + }); + + let document_stub_properties = document_stub_properties_value + .into_btree_string_map() + .map_err(|e| Error::Protocol(ProtocolError::ValueError(e)))?; + + let document = DocumentV0 { + id: DPNS_DASH_TLD_DOCUMENT_ID.into(), + properties: document_stub_properties, + owner_id: contract.owner_id(), + revision: None, + created_at: Some(genesis_time), + updated_at: Some(genesis_time), + transferred_at: Some(genesis_time), + created_at_block_height: None, + updated_at_block_height: None, + transferred_at_block_height: None, + created_at_core_block_height: None, + updated_at_core_block_height: None, + transferred_at_core_block_height: None, + } + .into(); + + let document_type = contract.document_type_for_name("domain")?; + + let operation = DriveOperation::DocumentOperation(DocumentOperationType::AddDocument { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentInfo::DocumentOwnedInfo((document, None)), + owner_id: None, + }, + contract_info: DataContractInfo::BorrowedDataContract(contract), + document_type_info: DocumentTypeInfo::DocumentTypeRef(document_type), + override_document: false, + }); + + operations.push(operation); + + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/mod.rs index e046d8bc3d..72819eb993 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/mod.rs @@ -6,7 +6,9 @@ use dpp::prelude::CoreBlockHeight; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; +mod common; pub mod v0; +pub mod v1; impl Platform { /// Creates trees and populates them with necessary identities, contracts and documents @@ -29,9 +31,15 @@ impl Platform { transaction, platform_version, ), + 1 => self.create_genesis_state_v1( + genesis_core_height, + genesis_time, + transaction, + platform_version, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "create_genesis_state".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs index e343d710c8..89f8ccd79e 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v0/mod.rs @@ -1,27 +1,13 @@ use crate::error::Error; use crate::platform_types::platform::Platform; -use dpp::platform_value::platform_value; -use dpp::ProtocolError; - use drive::dpp::identity::TimestampMillis; use dpp::block::block_info::BlockInfo; -use dpp::data_contract::accessors::v0::DataContractV0Getters; -use dpp::data_contract::DataContract; -use dpp::document::DocumentV0; -use dpp::serialization::PlatformSerializableWithPlatformVersion; +use dpp::prelude::CoreBlockHeight; use dpp::version::PlatformVersion; use drive::dpp::system_data_contracts::SystemDataContract; -use drive::util::batch::{DataContractOperationType, DocumentOperationType, DriveOperation}; - -use dpp::prelude::CoreBlockHeight; -use dpp::system_data_contracts::dpns_contract::DPNS_DASH_TLD_DOCUMENT_ID; use drive::query::TransactionArg; -use drive::util::object_size_info::{ - DataContractInfo, DocumentInfo, DocumentTypeInfo, OwnedDocumentInfo, -}; -use std::borrow::Cow; use std::collections::BTreeMap; impl Platform { @@ -92,83 +78,6 @@ impl Platform { Ok(()) } - - fn register_system_data_contract_operations<'a>( - &self, - data_contract: &'a DataContract, - operations: &mut Vec>, - platform_version: &PlatformVersion, - ) -> Result<(), Error> { - let serialization = - data_contract.serialize_to_bytes_with_platform_version(platform_version)?; - operations.push(DriveOperation::DataContractOperation( - DataContractOperationType::ApplyContractWithSerialization { - contract: Cow::Borrowed(data_contract), - serialized_contract: serialization, - storage_flags: None, - }, - )); - Ok(()) - } - - fn register_dpns_top_level_domain_operations<'a>( - &'a self, - contract: &'a DataContract, - genesis_time: TimestampMillis, - operations: &mut Vec>, - ) -> Result<(), Error> { - let domain = "dash"; - - let document_stub_properties_value = platform_value!({ - "label" : domain, - "normalizedLabel" : domain, - "parentDomainName" : "", - "normalizedParentDomainName" : "", - "records" : { - "identity" : contract.owner_id(), - }, - "subdomainRules": { - "allowSubdomains": true, - } - }); - - let document_stub_properties = document_stub_properties_value - .into_btree_string_map() - .map_err(|e| Error::Protocol(ProtocolError::ValueError(e)))?; - - let document = DocumentV0 { - id: DPNS_DASH_TLD_DOCUMENT_ID.into(), - properties: document_stub_properties, - owner_id: contract.owner_id(), - revision: None, - created_at: Some(genesis_time), - updated_at: Some(genesis_time), - transferred_at: Some(genesis_time), - created_at_block_height: None, - updated_at_block_height: None, - transferred_at_block_height: None, - created_at_core_block_height: None, - updated_at_core_block_height: None, - transferred_at_core_block_height: None, - } - .into(); - - let document_type = contract.document_type_for_name("domain")?; - - let operation = DriveOperation::DocumentOperation(DocumentOperationType::AddDocument { - owned_document_info: OwnedDocumentInfo { - document_info: DocumentInfo::DocumentOwnedInfo((document, None)), - owner_id: None, - }, - contract_info: DataContractInfo::BorrowedDataContract(contract), - document_type_info: DocumentTypeInfo::DocumentTypeRef(document_type), - override_document: false, - }); - - operations.push(operation); - - Ok(()) - } } #[cfg(test)] diff --git a/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v1/mod.rs new file mode 100644 index 0000000000..d6a1cf7039 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/initialization/create_genesis_state/v1/mod.rs @@ -0,0 +1,125 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; + +use drive::dpp::identity::TimestampMillis; + +use dpp::block::block_info::BlockInfo; +use dpp::prelude::CoreBlockHeight; +use dpp::version::PlatformVersion; +use drive::dpp::system_data_contracts::SystemDataContract; +use drive::query::TransactionArg; +use std::collections::BTreeMap; + +impl Platform { + /// Creates trees and populates them with necessary identities, contracts and documents + #[inline(always)] + pub(super) fn create_genesis_state_v1( + &self, + genesis_core_height: CoreBlockHeight, + genesis_time: TimestampMillis, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + //versioned call + self.drive + .create_initial_state_structure(transaction, platform_version)?; + + self.drive + .store_genesis_core_height(genesis_core_height, transaction, platform_version)?; + + let mut operations = vec![]; + + // Create system identities and contracts + + let system_data_contracts = &self.drive.cache.system_data_contracts; + + let system_data_contract_types = BTreeMap::from_iter([ + (SystemDataContract::DPNS, system_data_contracts.load_dpns()), + ( + SystemDataContract::Withdrawals, + system_data_contracts.load_withdrawals(), + ), + ( + SystemDataContract::Dashpay, + system_data_contracts.load_dashpay(), + ), + ( + SystemDataContract::MasternodeRewards, + system_data_contracts.load_masternode_reward_shares(), + ), + ( + SystemDataContract::TokenHistory, + system_data_contracts.load_token_history(), + ), + ]); + //todo add Wallet Utils (maybe) + + for data_contract in system_data_contract_types.values() { + self.register_system_data_contract_operations( + data_contract, + &mut operations, + platform_version, + )?; + } + + let dpns_contract = system_data_contracts.load_dpns(); + + self.register_dpns_top_level_domain_operations( + &dpns_contract, + genesis_time, + &mut operations, + )?; + + let block_info = BlockInfo::default_with_time(genesis_time); + + self.drive.apply_drive_operations( + operations, + true, + &block_info, + transaction, + platform_version, + None, // No previous_fee_versions needed for genesis state creation + )?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + mod create_genesis_state { + use crate::config::PlatformConfig; + use crate::test::helpers::setup::TestPlatformBuilder; + use drive::config::DriveConfig; + use platform_version::version::{PlatformVersion, INITIAL_PROTOCOL_VERSION}; + + #[test] + pub fn should_create_genesis_state_deterministically() { + let platform_version = PlatformVersion::first(); + let platform = TestPlatformBuilder::new() + .with_config(PlatformConfig { + drive: DriveConfig { + epochs_per_era: 20, + ..Default::default() + }, + ..Default::default() + }) + .with_initial_protocol_version(INITIAL_PROTOCOL_VERSION) + .build_with_mock_rpc() + .set_genesis_state(); + + let root_hash = platform + .drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .expect("should obtain root hash"); + + // This should never be changed + assert_eq!( + hex::encode(root_hash), + "dc5b0d4be407428adda2315db7d782e64015cbe2d2b7df963f05622390dc3c9f" + ) + } + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/mod.rs index 41b64d63b1..1ac0715b9d 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/mod.rs @@ -1,7 +1,7 @@ /// Methods occurring at the finalization of a block pub(in crate::execution) mod block_end; /// Block fee processing -pub(in crate::execution) mod block_fee_processing; +pub(in crate::execution) mod block_processing_end_events; /// Events happening what starting to process a block pub(in crate::execution) mod block_start; /// Update from core such as a masternode list update or quorums being updated @@ -22,6 +22,7 @@ pub(in crate::execution) mod initialization; pub(in crate::execution) mod protocol_upgrade; /// State transition processing pub(in crate::execution) mod state_transition_processing; +mod tokens; /// Voting pub(in crate::execution) mod voting; /// Withdrawal methods diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs index 27a10ad10c..4f65b48978 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs @@ -13,6 +13,7 @@ use dpp::system_data_contracts::load_system_data_contract; use dpp::version::PlatformVersion; use dpp::version::ProtocolVersion; use dpp::voting::vote_polls::VotePoll; +use drive::drive::balances::TOTAL_TOKEN_SUPPLIES_STORAGE_KEY; use drive::drive::identity::key::fetch::{ IdentityKeysRequest, KeyIDIdentityPublicKeyPairBTreeMap, KeyRequestType, }; @@ -24,8 +25,14 @@ use drive::drive::prefunded_specialized_balances::{ prefunded_specialized_balances_for_voting_path, prefunded_specialized_balances_for_voting_path_vec, }; +use drive::drive::system::misc_path; +use drive::drive::tokens::paths::{ + tokens_root_path, TOKEN_BALANCES_KEY, TOKEN_IDENTITY_INFO_KEY, TOKEN_STATUS_INFO_KEY, +}; use drive::drive::votes::paths::vote_end_date_queries_tree_path_vec; +use drive::drive::RootTree; use drive::grovedb::{Element, PathQuery, Query, QueryItem, SizedQuery, Transaction}; +use drive::grovedb_path::SubtreePath; use drive::query::QueryResultType; use std::collections::HashSet; use std::ops::RangeFull; @@ -79,12 +86,16 @@ impl Platform { "Error while transitioning to version 8: {e}" ); - // We ignore this transition errors because it's not changing the state stucture + // We ignore this transition errors because it's not changing the state structure // and not critical for the system Ok::<(), Error>(()) })?; } + if previous_protocol_version < 9 && platform_version.protocol_version >= 9 { + self.transition_to_version_9(block_info, transaction, platform_version)?; + } + Ok(()) } @@ -238,6 +249,77 @@ impl Platform { Ok(()) } + /// Adds all trees needed for tokens, also adds the token history system data contract + /// + /// This function is called during the transition from protocol version 5 to protocol version 6 + /// and higher to set up the wallet contract in the platform. + fn transition_to_version_9( + &self, + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + self.drive.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::GroupActions as u8], + Some(transaction), + None, + &mut vec![], + &platform_version.drive, + )?; + + let path = tokens_root_path(); + self.drive.grove_insert_if_not_exists( + (&path).into(), + &[TOKEN_BALANCES_KEY], + Element::empty_big_sum_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + self.drive.grove_insert_if_not_exists( + (&path).into(), + &[TOKEN_IDENTITY_INFO_KEY], + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + self.drive.grove_insert_if_not_exists( + (&path).into(), + &[TOKEN_STATUS_INFO_KEY], + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + let path = misc_path(); + self.drive.grove_insert_if_not_exists( + (&path).into(), + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY.as_slice(), + Element::empty_big_sum_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + let contract = + load_system_data_contract(SystemDataContract::TokenHistory, platform_version)?; + + self.drive.insert_contract( + &contract, + *block_info, + true, + Some(transaction), + platform_version, + )?; + + Ok(()) + } + /// Initializes an empty sum tree for withdrawal transactions required for protocol version 4. /// /// This function is called during the transition to protocol version 4 to set up diff --git a/packages/rs-drive-abci/src/execution/platform_events/tokens/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/tokens/mod.rs new file mode 100644 index 0000000000..b3c9f415e5 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/tokens/mod.rs @@ -0,0 +1 @@ +mod validate_token_aggregated_balance; diff --git a/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/mod.rs new file mode 100644 index 0000000000..68718a29b6 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/mod.rs @@ -0,0 +1,54 @@ +mod v0; + +use dpp::version::PlatformVersion; + +use drive::grovedb::Transaction; + +use crate::error::execution::ExecutionError; +use crate::error::Error; + +use crate::platform_types::platform::Platform; + +impl Platform { + /// Validates the aggregated token balance for the platform. + /// + /// This function verifies that the total token balances in the platform are consistent + /// and correctly aggregated. It delegates the validation to a version-specific implementation + /// based on the `PlatformVersion` provided. + /// + /// # Arguments + /// + /// * `transaction` - A reference to the current transaction. + /// * `platform_version` - The platform version specifying the implementation to use. + /// + /// # Returns + /// + /// * `Ok(())` if the token balances are validated successfully. + /// * `Err(Error)` if the validation fails due to inconsistencies or an unknown version. + /// + /// # Errors + /// + /// Returns an `ExecutionError::CorruptedCreditsNotBalanced` if the token sum trees + /// are not balanced. + /// + /// Returns an `ExecutionError::UnknownVersionMismatch` if the platform version is not recognized. + pub fn validate_token_aggregated_balance( + &self, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive_abci + .methods + .tokens_processing + .validate_token_aggregated_balance + { + 0 => self.validate_token_aggregated_balance_v0(transaction, platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "validate_token_aggregated_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs new file mode 100644 index 0000000000..072d8dfc7e --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs @@ -0,0 +1,37 @@ +use drive::grovedb::Transaction; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use dpp::version::PlatformVersion; + +impl Platform { + #[inline(always)] + pub(super) fn validate_token_aggregated_balance_v0( + &self, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + if self.config.execution.verify_token_sum_trees { + // Verify sum trees + let token_balance = self + .drive + .calculate_total_tokens_balance(Some(transaction), &platform_version.drive) + .map_err(Error::Drive)?; + + if !token_balance.ok()? { + return Err(Error::Execution( + ExecutionError::CorruptedCreditsNotBalanced(format!( + "credits are not balanced after block execution {:?} off by {}", + token_balance, + token_balance + .total_identity_token_balances + .abs_diff(token_balance.total_tokens_in_platform) + )), + )); + } + } + + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/withdrawals/cleanup_expired_locks_of_withdrawal_amounts/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/withdrawals/cleanup_expired_locks_of_withdrawal_amounts/v0/mod.rs index 74315a1d6c..0c4ab33a05 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/withdrawals/cleanup_expired_locks_of_withdrawal_amounts/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/withdrawals/cleanup_expired_locks_of_withdrawal_amounts/v0/mod.rs @@ -6,7 +6,7 @@ use dpp::block::block_info::BlockInfo; use dpp::version::PlatformVersion; use drive::drive::identity::withdrawals::paths::get_withdrawal_transactions_sum_tree_path_vec; -use drive::grovedb::{PathQuery, QueryItem, Transaction}; +use drive::grovedb::{MaybeTree, PathQuery, QueryItem, Transaction}; use drive::util::grove_operations::BatchDeleteApplyType; impl Platform @@ -49,7 +49,7 @@ where true, // we know that we are not deleting a subtree BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, Some(transaction), &mut batch_operations, diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index 1150faaca1..73c87119d0 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -162,7 +162,7 @@ impl<'a> ExecutionEvent<'a> { ))) } } - StateTransitionAction::DocumentsBatchAction(document_batch_action) => { + StateTransitionAction::BatchAction(document_batch_action) => { let user_fee_increase = action.user_fee_increase(); let removed_balance = document_batch_action.all_used_balances()?; let operations = diff --git a/packages/rs-drive-abci/src/execution/types/execution_operation/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_operation/mod.rs index d44b854495..c0dc1fa91e 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_operation/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_operation/mod.rs @@ -65,6 +65,7 @@ pub const SHA256_BLOCK_SIZE: u16 = 64; #[derive(Debug, Clone, PartialEq, Eq)] pub enum ValidationOperation { Protocol(ProtocolValidationOperation), + RetrieveIdentityTokenBalance, RetrieveIdentity(RetrieveIdentityInfo), RetrievePrefundedSpecializedBalance, PerformNetworkThresholdSigning, @@ -224,6 +225,19 @@ impl ValidationOperation { "execution processing fee overflow error", ))?; } + ValidationOperation::RetrieveIdentityTokenBalance => { + let operation_cost = platform_version + .fee_version + .processing + .fetch_identity_token_balance_processing_cost; + + fee_result.processing_fee = fee_result + .processing_fee + .checked_add(operation_cost) + .ok_or(ExecutionError::Overflow( + "execution processing fee overflow error", + ))?; + } } } Ok(()) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/transaction/fetch_asset_lock_transaction_output_sync/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/transaction/fetch_asset_lock_transaction_output_sync/v0/mod.rs index 0f11ba2a64..b48a79bf8e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/transaction/fetch_asset_lock_transaction_output_sync/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/transaction/fetch_asset_lock_transaction_output_sync/v0/mod.rs @@ -49,7 +49,7 @@ pub fn fetch_asset_lock_transaction_output_sync_v0( let Some(transaction_info) = maybe_transaction_info else { // Transaction hash bytes needs to be reversed to match actual transaction hash - let mut hash: [u8; 32] = *transaction_hash.as_raw_hash().as_byte_array(); + let mut hash: [u8; 32] = transaction_hash.as_raw_hash().to_byte_array(); hash.reverse(); return Ok(ValidationResult::new_with_error( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs index 6f9cfb87ad..9a9e2f8901 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_simple_pre_check_balance/v0/mod.rs @@ -33,7 +33,7 @@ impl ValidateSimplePreCheckBalanceV0 for StateTransition { .state_transition_min_fees .contract_update } - StateTransition::DocumentsBatch(_) => { + StateTransition::Batch(_) => { platform_version .fee_version .state_transition_min_fees diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs index c3f10fa275..12d7bdd4e0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs @@ -528,7 +528,7 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { StateTransition::IdentityCreditWithdrawal(st) => { st.validate_basic_structure(platform_version) } - StateTransition::DocumentsBatch(st) => st.validate_basic_structure(platform_version), + StateTransition::Batch(st) => st.validate_basic_structure(platform_version), StateTransition::IdentityCreditTransfer(st) => { st.validate_basic_structure(platform_version) } @@ -554,7 +554,7 @@ impl StateTransitionNonceValidationV0 for StateTransition { platform_version: &PlatformVersion, ) -> Result { match self { - StateTransition::DocumentsBatch(st) => st.validate_nonces( + StateTransition::Batch(st) => st.validate_nonces( platform, block_info, tx, @@ -618,7 +618,7 @@ impl StateTransitionHasNonceValidationV0 for StateTransition { 0 => { let has_nonce_validation = matches!( self, - StateTransition::DocumentsBatch(_) + StateTransition::Batch(_) | StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::IdentityUpdate(_) @@ -632,7 +632,7 @@ impl StateTransitionHasNonceValidationV0 for StateTransition { // Preferably to use match without wildcard arm (_) to avoid missing cases // in the future when new state transitions are added let has_nonce_validation = match self { - StateTransition::DocumentsBatch(_) + StateTransition::Batch(_) | StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::IdentityUpdate(_) @@ -666,7 +666,7 @@ impl StateTransitionIdentityBalanceValidationV0 for StateTransition { StateTransition::IdentityCreditWithdrawal(st) => { st.validate_minimum_balance_pre_check(identity, platform_version) } - StateTransition::DocumentsBatch(st) => { + StateTransition::Batch(st) => { st.validate_minimum_balance_pre_check(identity, platform_version) } StateTransition::DataContractCreate(_) @@ -687,7 +687,7 @@ impl StateTransitionIdentityBalanceValidationV0 for StateTransition { | StateTransition::IdentityCreditWithdrawal(_) | StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) - | StateTransition::DocumentsBatch(_) + | StateTransition::Batch(_) | StateTransition::IdentityUpdate(_) ) } @@ -790,7 +790,7 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition { platform_version: &PlatformVersion, ) -> Result, Error> { match self { - StateTransition::DocumentsBatch(st) => st.validate_advanced_structure_from_state( + StateTransition::Batch(st) => st.validate_advanced_structure_from_state( block_info, network, action, @@ -829,7 +829,7 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition { fn has_advanced_structure_validation_with_state(&self) -> bool { matches!( self, - StateTransition::DocumentsBatch(_) + StateTransition::Batch(_) | StateTransition::IdentityCreate(_) | StateTransition::MasternodeVote(_) ) @@ -838,7 +838,7 @@ impl StateTransitionStructureKnownInStateValidationV0 for StateTransition { /// This means we should transform into the action before validation of the advanced structure, /// and that we must even do this on check_tx fn requires_advanced_structure_validation_with_state_on_check_tx(&self) -> bool { - matches!(self, StateTransition::DocumentsBatch(_)) + matches!(self, StateTransition::Batch(_)) } } @@ -854,7 +854,7 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::IdentityCreditTransfer(_) - | StateTransition::DocumentsBatch(_) => { + | StateTransition::Batch(_) => { //Basic signature verification Ok(self.validate_state_transition_identity_signed( drive, @@ -1029,7 +1029,7 @@ impl StateTransitionStateValidationV0 for StateTransition { tx, ), // The replay attack is prevented by identity data contract nonce - StateTransition::DocumentsBatch(st) => st.validate_state( + StateTransition::Batch(st) => st.validate_state( action, platform, validation_mode, @@ -1060,7 +1060,7 @@ impl StateTransitionStateValidationV0 for StateTransition { impl StateTransitionIsAllowedValidationV0 for StateTransition { fn has_is_allowed_validation(&self, platform_version: &PlatformVersion) -> Result { match self { - StateTransition::DocumentsBatch(st) => st.has_is_allowed_validation(platform_version), + StateTransition::Batch(st) => st.has_is_allowed_validation(platform_version), StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::IdentityCreate(_) @@ -1078,9 +1078,7 @@ impl StateTransitionIsAllowedValidationV0 for StateTransition { platform_version: &PlatformVersion, ) -> Result, Error> { match self { - StateTransition::DocumentsBatch(st) => { - st.validate_is_allowed(platform, platform_version) - } + StateTransition::Batch(st) => st.validate_is_allowed(platform, platform_version), _ => Err(Error::Execution(ExecutionError::CorruptedCodeExecution( "validate_is_allowed is not implemented for this state transition", ))), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/mod.rs similarity index 83% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/mod.rs index 7dfa5e8eba..56c8458ced 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/mod.rs @@ -2,15 +2,15 @@ use dashcore_rpc::dashcore::Network; use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionAction; 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::documents_batch::action_validation::document_create_transition_action::state_v0::DocumentCreateTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_create_transition_action::state_v1::DocumentCreateTransitionActionStateValidationV1; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_create_transition_action::structure_v0::DocumentCreateTransitionActionStructureValidationV0; +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::platform_types::platform::PlatformStateRef; mod state_v0; @@ -49,7 +49,7 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_create_transition_structure_validation { 0 => self.validate_structure_v0(owner_id, block_info, network, platform_version), @@ -74,7 +74,7 @@ impl DocumentCreateTransitionActionValidation for DocumentCreateTransitionAction .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_create_transition_state_validation { 0 => self.validate_state_v0( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/state_v0/mod.rs similarity index 96% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/state_v0/mod.rs index fdc1c0a2df..aa752dc2fd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/state_v0/mod.rs @@ -10,8 +10,8 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::prelude::{ConsensusValidationResult, Identifier}; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::{ContestedDocumentVotePollStatus, ContestedDocumentVotePollStoredInfoV0Getters}; use drive::error::drive::DriveError; @@ -19,8 +19,8 @@ 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::documents_batch::state::v0::fetch_contender::fetch_contender; -use crate::execution::validation::state_transition::documents_batch::state::v0::fetch_documents::fetch_document_with_id; +use crate::execution::validation::state_transition::batch::state::v0::fetch_contender::fetch_contender; +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 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/state_v1/mod.rs similarity index 96% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/state_v1/mod.rs index 2e2908d9b5..14cb413f30 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/state_v1/mod.rs @@ -12,8 +12,8 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::prelude::{ConsensusValidationResult, Identifier}; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::{ContestedDocumentVotePollStatus, ContestedDocumentVotePollStoredInfoV0Getters}; use drive::error::drive::DriveError; @@ -21,8 +21,8 @@ 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::documents_batch::state::v0::fetch_contender::fetch_contender; -use crate::execution::validation::state_transition::documents_batch::state::v0::fetch_documents::{fetch_document_with_id, has_contested_document_with_document_id}; +use crate::execution::validation::state_transition::batch::state::v0::fetch_contender::fetch_contender; +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 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/structure_v0/mod.rs similarity index 97% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/structure_v0/mod.rs index 7ae98cf477..49b71dc021 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_create_transition_action/structure_v0/mod.rs @@ -9,8 +9,8 @@ use dpp::data_contract::document_type::restricted_creation::CreationRestrictionM use dpp::data_contract::validate_document::DataContractDocumentValidationMethodsV0; use dpp::identifier::Identifier; use dpp::validation::{SimpleConsensusValidationResult}; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/mod.rs similarity index 84% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/mod.rs index b36e68daa9..a3b7196204 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/mod.rs @@ -1,14 +1,14 @@ use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; 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::documents_batch::action_validation::document_delete_transition_action::state_v0::DocumentDeleteTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_delete_transition_action::structure_v0::DocumentDeleteTransitionActionStructureValidationV0; +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::platform_types::platform::PlatformStateRef; mod state_v0; @@ -40,7 +40,7 @@ impl DocumentDeleteTransitionActionValidation for DocumentDeleteTransitionAction .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_delete_transition_structure_validation { 0 => self.validate_structure_v0(), @@ -65,7 +65,7 @@ impl DocumentDeleteTransitionActionValidation for DocumentDeleteTransitionAction .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_delete_transition_state_validation { 0 => self.validate_state_v0( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/state_v0/mod.rs similarity index 92% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/state_v0/mod.rs index 98ce7ed92b..6ccb56aa5b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/state_v0/mod.rs @@ -9,15 +9,15 @@ use dpp::document::{Document, DocumentV0Getters}; use dpp::identifier::Identifier; use dpp::prelude::ConsensusValidationResult; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; 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::documents_batch::state::v0::fetch_documents::fetch_document_with_id; +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 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/structure_v0/mod.rs similarity index 91% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/structure_v0/mod.rs index 3813405201..347e495894 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_delete_transition_action/structure_v0/mod.rs @@ -2,9 +2,9 @@ use dpp::consensus::basic::document::{InvalidDocumentTransitionActionError, Inva use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; use crate::error::Error; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/mod.rs similarity index 84% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/mod.rs index ef6c32b996..8396ba0577 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/mod.rs @@ -2,14 +2,14 @@ use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; 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::documents_batch::action_validation::document_purchase_transition_action::state_v0::DocumentPurchaseTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_purchase_transition_action::structure_v0::DocumentPurchaseTransitionActionStructureValidationV0; +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::platform_types::platform::PlatformStateRef; mod state_v0; @@ -41,7 +41,7 @@ impl DocumentPurchaseTransitionActionValidation for DocumentPurchaseTransitionAc .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_purchase_transition_structure_validation { 0 => self.validate_structure_v0(platform_version), @@ -66,7 +66,7 @@ impl DocumentPurchaseTransitionActionValidation for DocumentPurchaseTransitionAc .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_purchase_transition_state_validation { 0 => self.validate_state_v0( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/state_v0/mod.rs similarity index 95% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/state_v0/mod.rs index 79e4311344..c5060437b7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/state_v0/mod.rs @@ -4,10 +4,10 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/structure_v0/mod.rs similarity index 95% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/structure_v0/mod.rs index afbe3ae28b..5a77bd645b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_purchase_transition_action/structure_v0/mod.rs @@ -4,8 +4,8 @@ use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::document::DocumentV0Getters; use dpp::nft::TradeMode; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/mod.rs similarity index 84% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/mod.rs index fe65d922dd..6392eb6870 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/mod.rs @@ -2,14 +2,14 @@ use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; 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::documents_batch::action_validation::document_replace_transition_action::state_v0::DocumentReplaceTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_replace_transition_action::structure_v0::DocumentReplaceTransitionActionStructureValidationV0; +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::platform_types::platform::PlatformStateRef; mod state_v0; @@ -41,7 +41,7 @@ impl DocumentReplaceTransitionActionValidation for DocumentReplaceTransitionActi .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_replace_transition_structure_validation { 0 => self.validate_structure_v0(platform_version), @@ -66,7 +66,7 @@ impl DocumentReplaceTransitionActionValidation for DocumentReplaceTransitionActi .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_replace_transition_state_validation { 0 => self.validate_state_v0( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/state_v0/mod.rs similarity index 95% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/state_v0/mod.rs index 8fea8e2856..01359fb61e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/state_v0/mod.rs @@ -4,10 +4,10 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/structure_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/structure_v0/mod.rs index 6f77359d1a..acb8488346 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_replace_transition_action/structure_v0/mod.rs @@ -3,8 +3,8 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::validate_document::DataContractDocumentValidationMethodsV0; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/mod.rs similarity index 84% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/mod.rs index 9b4f6e8b55..6a517d7140 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/mod.rs @@ -2,14 +2,14 @@ use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; 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::documents_batch::action_validation::document_transfer_transition_action::state_v0::DocumentTransferTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_transfer_transition_action::structure_v0::DocumentTransferTransitionActionStructureValidationV0; +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::platform_types::platform::PlatformStateRef; mod state_v0; @@ -41,7 +41,7 @@ impl DocumentTransferTransitionActionValidation for DocumentTransferTransitionAc .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_transfer_transition_structure_validation { 0 => self.validate_structure_v0(platform_version), @@ -66,7 +66,7 @@ impl DocumentTransferTransitionActionValidation for DocumentTransferTransitionAc .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_transfer_transition_state_validation { 0 => self.validate_state_v0( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/state_v0/mod.rs similarity index 95% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/state_v0/mod.rs index 7613df9afc..3a779e1302 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/state_v0/mod.rs @@ -4,10 +4,10 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/structure_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/structure_v0/mod.rs index 3910574a61..a8beba7bae 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_transfer_transition_action/structure_v0/mod.rs @@ -2,8 +2,8 @@ use dpp::consensus::basic::document::{InvalidDocumentTransitionActionError, Inva use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/mod.rs similarity index 84% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/mod.rs index 39a18561c0..b541eb15e1 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/mod.rs @@ -4,12 +4,12 @@ use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; use crate::error::Error; use crate::error::execution::ExecutionError; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::state_v0::DocumentUpdatePriceTransitionActionStateValidationV0; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::structure_v0::DocumentUpdatePriceTransitionActionStructureValidationV0; +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::platform_types::platform::PlatformStateRef; mod state_v0; @@ -41,7 +41,7 @@ impl DocumentUpdatePriceTransitionActionValidation for DocumentUpdatePriceTransi .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_transfer_transition_structure_validation { 0 => self.validate_structure_v0(platform_version), @@ -66,7 +66,7 @@ impl DocumentUpdatePriceTransitionActionValidation for DocumentUpdatePriceTransi .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .document_transfer_transition_state_validation { 0 => self.validate_state_v0( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/state_v0/mod.rs similarity index 95% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/state_v0/mod.rs index 43a72d50a5..9dc2abd730 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/state_v0/mod.rs @@ -4,10 +4,10 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::identifier::Identifier; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::platform_types::platform::PlatformStateRef; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/structure_v0/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/structure_v0/mod.rs index f8b66fe374..8635df40dd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_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_update_price_transition_action/structure_v0/mod.rs @@ -2,8 +2,8 @@ use dpp::consensus::basic::document::{InvalidDocumentTransitionActionError, Inva use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::validation::SimpleConsensusValidationResult; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::Error; 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 new file mode 100644 index 0000000000..f9872eec43 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/mod.rs @@ -0,0 +1,14 @@ +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; 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_base_transition_action/mod.rs new file mode 100644 index 0000000000..ed77bb370d --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/mod.rs @@ -0,0 +1,86 @@ +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 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::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; +} + +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_structure_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, + })), + } + } +} 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 new file mode 100644 index 0000000000..d072a906d3 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/state_v0/mod.rs @@ -0,0 +1,67 @@ +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/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_base_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..034d208c51 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_base_transition_action/structure_v0/mod.rs @@ -0,0 +1,49 @@ +use dpp::consensus::basic::BasicError; +use dpp::consensus::basic::token::ContractHasNoTokensError; +use dpp::consensus::basic::token::InvalidTokenPositionError; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +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 crate::error::Error; + +pub(super) trait TokenBaseTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenBaseTransitionActionStructureValidationV0 for TokenBaseTransitionAction { + fn validate_structure_v0( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + let token_position = self.token_position(); + let contract = self.data_contract_fetch_info_ref(); + if contract.contract.tokens().get(&token_position).is_none() { + return if contract.contract.tokens().is_empty() { + Ok(SimpleConsensusValidationResult::new_with_error( + BasicError::ContractHasNoTokensError(ContractHasNoTokensError::new( + contract.contract.id(), + )) + .into(), + )) + } else { + Ok(SimpleConsensusValidationResult::new_with_error( + BasicError::InvalidTokenPositionError(InvalidTokenPositionError::new( + *contract + .contract + .tokens() + .keys() + .last() + .expect("we already checked this was not empty"), + token_position, + )) + .into(), + )) + }; + } + Ok(SimpleConsensusValidationResult::default()) + } +} 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_burn_transition_action/mod.rs new file mode 100644 index 0000000000..0ed8bdfb4d --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/mod.rs @@ -0,0 +1,86 @@ +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_burn_transition_action::TokenBurnTransitionAction; +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_burn_transition_action::state_v0::TokenBurnTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token_burn_transition_action::structure_v0::TokenBurnTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenBurnTransitionActionValidation { + 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; +} + +impl TokenBurnTransitionActionValidation for TokenBurnTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_burn_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenBurnTransitionAction::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_burn_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: "TokenBurnTransitionAction::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_burn_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..85ad0983ef --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_transition_action/state_v0/mod.rs @@ -0,0 +1,108 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, 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::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 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::platform_types::platform::PlatformStateRef; + +pub(super) trait TokenBurnTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenBurnTransitionActionStateValidationV0 for TokenBurnTransitionAction { + 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_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(), + 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(), + ), + )), + )); + } + + // We need to verify that we have enough of the token + let balance = platform + .drive + .fetch_identity_token_balance( + self.token_id().to_buffer(), + owner_id.to_buffer(), + transaction, + platform_version, + )? + .unwrap_or_default(); + execution_context.add_operation(ValidationOperation::RetrieveIdentityTokenBalance); + if balance < self.burn_amount() { + // The identity does not exist + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityDoesNotHaveEnoughTokenBalanceError( + IdentityDoesNotHaveEnoughTokenBalanceError::new( + self.token_id(), + owner_id, + self.burn_amount(), + balance, + "burn".to_string(), + ), + )), + )); + } + + Ok(SimpleConsensusValidationResult::new()) + } +} 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_burn_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..3529a60558 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_burn_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_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; + +pub(super) trait TokenBurnTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenBurnTransitionActionStructureValidationV0 for TokenBurnTransitionAction { + 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_destroy_frozen_funds_transition_action/mod.rs new file mode 100644 index 0000000000..9b8428f51d --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/mod.rs @@ -0,0 +1,86 @@ +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_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionAction; +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_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::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenDestroyFrozenFundsTransitionActionValidation { + 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; +} + +impl TokenDestroyFrozenFundsTransitionActionValidation for TokenDestroyFrozenFundsTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_destroy_frozen_funds_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenDestroyFrozenFundsTransitionAction::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_destroy_frozen_funds_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: "TokenDestroyFrozenFundsTransitionAction::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_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_destroy_frozen_funds_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..99bf2b350c --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/state_v0/mod.rs @@ -0,0 +1,109 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::{IdentityTokenAccountNotFrozenError, 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::prelude::Identifier; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +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 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::platform_types::platform::PlatformStateRef; + +pub(super) trait TokenDestroyFrozenFundsTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenDestroyFrozenFundsTransitionActionStateValidationV0 + for TokenDestroyFrozenFundsTransitionAction +{ + 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); + } + + // We need to validate that we are frozen + + let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs( + self.token_id().to_buffer(), + self.frozen_identity_id().to_buffer(), + block_info, + true, + transaction, + platform_version, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + if info.is_none() || !info.unwrap().frozen() { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityTokenAccountNotFrozenError( + IdentityTokenAccountNotFrozenError::new( + self.token_id(), + self.frozen_identity_id(), + "destroy_frozen_funds".to_string(), + ), + )), + )); + } + + // 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.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(), + 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(), + ), + )), + )); + } + + 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_destroy_frozen_funds_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..2f0c22d417 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_destroy_frozen_funds_transition_action/structure_v0/mod.rs @@ -0,0 +1,27 @@ +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; + +pub(super) trait TokenDestroyFrozenFundsTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenDestroyFrozenFundsTransitionActionStructureValidationV0 + for TokenDestroyFrozenFundsTransitionAction +{ + 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_emergency_action_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/mod.rs new file mode 100644 index 0000000000..a78f9e9537 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/mod.rs @@ -0,0 +1,86 @@ +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_emergency_action_transition_action::TokenEmergencyActionTransitionAction; +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_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::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenEmergencyActionTransitionActionValidation { + 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; +} + +impl TokenEmergencyActionTransitionActionValidation for TokenEmergencyActionTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_emergency_action_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenEmergencyActionTransitionAction::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_emergency_action_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: "TokenEmergencyActionTransitionAction::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_emergency_action_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..c5ea53f9b0 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/state_v0/mod.rs @@ -0,0 +1,83 @@ +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::multi_identity_events::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}; +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::platform_types::platform::PlatformStateRef; + +pub(super) trait TokenEmergencyActionTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenEmergencyActionTransitionActionStateValidationV0 + for TokenEmergencyActionTransitionAction +{ + 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.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(), + 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(), + ), + )), + )); + } + + 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_emergency_action_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..cc4f6b8d25 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_emergency_action_transition_action/structure_v0/mod.rs @@ -0,0 +1,27 @@ +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; + +pub(super) trait TokenEmergencyActionTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenEmergencyActionTransitionActionStructureValidationV0 + for TokenEmergencyActionTransitionAction +{ + 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_freeze_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/mod.rs new file mode 100644 index 0000000000..47777b8d73 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/mod.rs @@ -0,0 +1,86 @@ +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_freeze_transition_action::TokenFreezeTransitionAction; +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_freeze_transition_action::state_v0::TokenFreezeTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token_freeze_transition_action::structure_v0::TokenFreezeTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenFreezeTransitionActionValidation { + 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; +} + +impl TokenFreezeTransitionActionValidation for TokenFreezeTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_freeze_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenFreezeTransitionAction::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_freeze_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: "TokenFreezeTransitionAction::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_freeze_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..507f02c281 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_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::multi_identity_events::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}; +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::platform_types::platform::PlatformStateRef; + +pub(super) trait TokenFreezeTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenFreezeTransitionActionStateValidationV0 for TokenFreezeTransitionAction { + 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.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(), + 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(), + ), + )), + )); + } + + 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_freeze_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..8b754e60e7 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_freeze_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_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; + +pub(super) trait TokenFreezeTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenFreezeTransitionActionStructureValidationV0 for TokenFreezeTransitionAction { + 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_mint_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/mod.rs new file mode 100644 index 0000000000..f8cd83b7a6 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/mod.rs @@ -0,0 +1,86 @@ +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_mint_transition_action::TokenMintTransitionAction; +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_mint_transition_action::state_v0::TokenMintTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token_mint_transition_action::structure_v0::TokenMintTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenMintTransitionActionValidation { + 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; +} + +impl TokenMintTransitionActionValidation for TokenMintTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_mint_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenMintTransitionAction::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_issuance_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: "TokenMintTransitionAction::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_mint_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..7653477deb --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_transition_action/state_v0/mod.rs @@ -0,0 +1,166 @@ +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::multi_identity_events::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_base_transition_action::TokenBaseTransitionActionValidation; +use crate::platform_types::platform::PlatformStateRef; + +pub(super) 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() + .map(|position| contract.expected_group(position)) + .transpose()?; + + if let Some(resolved_group_info) = self.base().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 + match rules.authorized_to_make_change_action_takers() { + AuthorizedActionTakers::NoOne | AuthorizedActionTakers::ContractOwner => { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::UnauthorizedTokenActionError( + UnauthorizedTokenActionError::new( + self.token_id(), + owner_id, + "mint".to_string(), + rules.authorized_to_make_change_action_takers().clone(), + ), + )), + )) + } + AuthorizedActionTakers::MainGroup => { + if let Some(main_control_group_contract_position) = + token_configuration.main_control_group() + { + if main_control_group_contract_position + != resolved_group_info.group_contract_position + { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError( + StateError::UnauthorizedTokenActionError( + UnauthorizedTokenActionError::new( + self.token_id(), + owner_id, + "mint".to_string(), + rules.authorized_to_make_change_action_takers().clone(), + ), + ), + ), + )); + } + } + } + AuthorizedActionTakers::Group(group_contract_position) => { + if *group_contract_position != resolved_group_info.group_contract_position { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::UnauthorizedTokenActionError( + UnauthorizedTokenActionError::new( + self.token_id(), + owner_id, + "mint".to_string(), + rules.authorized_to_make_change_action_takers().clone(), + ), + )), + )); + } + } + } + } else { + if !rules.can_make_change( + &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, + "mint".to_string(), + rules.authorized_to_make_change_action_takers().clone(), + ), + )), + )); + } + } + + // 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_mint_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..33648a7e26 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_mint_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_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; + +pub(super) trait TokenMintTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenMintTransitionActionStructureValidationV0 for TokenMintTransitionAction { + 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_transfer_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/mod.rs new file mode 100644 index 0000000000..2d9754412f --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/mod.rs @@ -0,0 +1,88 @@ +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_transfer_transition_action::TokenTransferTransitionAction; +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_transfer_transition_action::state_v0::TokenTransferTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token_transfer_transition_action::structure_v0::TokenTransferTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenTransferTransitionActionValidation { + fn validate_structure( + &self, + owner_id: Identifier, + 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; +} + +impl TokenTransferTransitionActionValidation for TokenTransferTransitionAction { + fn validate_structure( + &self, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_transfer_transition_structure_validation + { + 0 => self.validate_structure_v0(owner_id, platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenTransferTransitionAction::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_issuance_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: "TokenTransferTransitionAction::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_transfer_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..04336501c9 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/state_v0/mod.rs @@ -0,0 +1,103 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountFrozenError}; +use dpp::prelude::Identifier; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +use dpp::validation::SimpleConsensusValidationResult; +use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::{TokenTransferTransitionAction}; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; +use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionAccessorsV0; +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::platform_types::platform::PlatformStateRef; + +pub(super) trait TokenTransferTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenTransferTransitionActionStateValidationV0 for TokenTransferTransitionAction { + 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); + } + + // We need to verify that we have enough of the token + let balance = platform + .drive + .fetch_identity_token_balance( + self.token_id().to_buffer(), + owner_id.to_buffer(), + transaction, + platform_version, + )? + .unwrap_or_default(); + execution_context.add_operation(ValidationOperation::RetrieveIdentityTokenBalance); + if balance < self.amount() { + // The identity does not exist + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityDoesNotHaveEnoughTokenBalanceError( + IdentityDoesNotHaveEnoughTokenBalanceError::new( + self.token_id(), + owner_id, + self.amount(), + balance, + "transfer".to_string(), + ), + )), + )); + } + + // We need to verify that our token account is not frozen + + // We need to verify that we have enough of the token + let info = platform.drive.fetch_identity_token_info( + self.token_id().to_buffer(), + owner_id.to_buffer(), + transaction, + platform_version, + )?; + if let Some(info) = info { + // We have an info, we need to check that we are not frozen + if info.frozen() == true { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityTokenAccountFrozenError( + IdentityTokenAccountFrozenError::new( + self.token_id(), + owner_id, + "transfer".to_string(), + ), + )), + )); + } + }; + + Ok(SimpleConsensusValidationResult::new()) + } +} 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_transfer_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..92747e6d4f --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_transfer_transition_action/structure_v0/mod.rs @@ -0,0 +1,29 @@ +use dpp::identifier::Identifier; +use dpp::validation::{SimpleConsensusValidationResult}; +use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionAction; +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; + +pub(super) trait TokenTransferTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenTransferTransitionActionStructureValidationV0 for TokenTransferTransitionAction { + fn validate_structure_v0( + &self, + _owner_id: Identifier, + 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_unfreeze_transition_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/mod.rs new file mode 100644 index 0000000000..0cb5f563fc --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/mod.rs @@ -0,0 +1,86 @@ +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_unfreeze_transition_action::TokenUnfreezeTransitionAction; +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_unfreeze_transition_action::state_v0::TokenUnfreezeTransitionActionStateValidationV0; +use crate::execution::validation::state_transition::batch::action_validation::token_unfreeze_transition_action::structure_v0::TokenUnfreezeTransitionActionStructureValidationV0; +use crate::platform_types::platform::PlatformStateRef; + +mod state_v0; +mod structure_v0; + +pub trait TokenUnfreezeTransitionActionValidation { + 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; +} + +impl TokenUnfreezeTransitionActionValidation for TokenUnfreezeTransitionAction { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .batch_state_transition + .token_unfreeze_transition_structure_validation + { + 0 => self.validate_structure_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "TokenUnfreezeTransitionAction::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_unfreeze_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: "TokenUnfreezeTransitionAction::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_unfreeze_transition_action/state_v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/state_v0/mod.rs new file mode 100644 index 0000000000..e8ba23d7f4 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_transition_action/state_v0/mod.rs @@ -0,0 +1,107 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::{IdentityTokenAccountNotFrozenError, 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::prelude::Identifier; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +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 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::platform_types::platform::PlatformStateRef; + +pub(super) trait TokenUnfreezeTransitionActionStateValidationV0 { + fn validate_state_v0( + &self, + platform: &PlatformStateRef, + owner_id: Identifier, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenUnfreezeTransitionActionStateValidationV0 for TokenUnfreezeTransitionAction { + 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); + } + + // We need to validate that we are frozen + + let (info, fee_result) = platform.drive.fetch_identity_token_info_with_costs( + self.token_id().to_buffer(), + self.frozen_identity_id().to_buffer(), + block_info, + true, + transaction, + platform_version, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + if info.is_none() || !info.unwrap().frozen() { + return Ok(SimpleConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityTokenAccountNotFrozenError( + IdentityTokenAccountNotFrozenError::new( + self.token_id(), + self.frozen_identity_id(), + "destroy_frozen_funds".to_string(), + ), + )), + )); + } + + // 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.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(), + 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(), + ), + )), + )); + } + + 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_unfreeze_transition_action/structure_v0/mod.rs new file mode 100644 index 0000000000..ba729c1f5e --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/action_validation/token_unfreeze_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_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; + +pub(super) trait TokenUnfreezeTransitionActionStructureValidationV0 { + fn validate_structure_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} +impl TokenUnfreezeTransitionActionStructureValidationV0 for TokenUnfreezeTransitionAction { + 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/documents_batch/advanced_structure/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/mod.rs 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 new file mode 100644 index 0000000000..d4da544dc9 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/advanced_structure/v0/mod.rs @@ -0,0 +1,339 @@ +use crate::error::Error; +use dpp::block::block_info::BlockInfo; +use dpp::consensus::basic::document::InvalidDocumentTransitionIdError; +use dpp::consensus::signature::{InvalidSignaturePublicKeySecurityLevelError, SignatureError}; +use dpp::dashcore::Network; +use dpp::document::Document; +use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; +use dpp::identity::PartialIdentity; +use dpp::state_transition::batch_transition::batched_transition::document_transition::DocumentTransition; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use dpp::state_transition::batch_transition::BatchTransition; +use dpp::state_transition::{StateTransitionIdentitySigned, StateTransitionLike}; +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::batch_transition::batched_transition::BatchedTransitionRef; +use dpp::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +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 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; +use drive::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::DocumentReplaceTransitionActionAccessorsV0; +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_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; +use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::TokenMintTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::token_transition::token_unfreeze_transition_action::TokenUnfreezeTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use drive::state_transition_action::StateTransitionAction; +use drive::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; +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; + +pub(in crate::execution::validation::state_transition::state_transitions::batch) trait DocumentsBatchStateTransitionStructureValidationV0 +{ + fn validate_advanced_structure_from_state_v0( + &self, + block_info: &BlockInfo, + network: Network, + action: &BatchTransitionAction, + identity: &PartialIdentity, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result, Error>; +} + +impl DocumentsBatchStateTransitionStructureValidationV0 for BatchTransition { + fn validate_advanced_structure_from_state_v0( + &self, + block_info: &BlockInfo, + network: Network, + action: &BatchTransitionAction, + identity: &PartialIdentity, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let security_levels = action.contract_based_security_level_requirement()?; + + let signing_key = identity.loaded_public_keys.get(&self.signature_public_key_id()).ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution("the key must exist for advanced structure validation as we already fetched it during signature validation")))?; + + if !security_levels.contains(&signing_key.security_level()) { + // We only need to bump the first identity data contract nonce as that will make a replay + // attack not possible + + let first_transition = self.first_transition().ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution("There must be at least one state transition as this is already verified in basic validation")))?; + + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_batched_transition_ref( + first_transition, + self.owner_id(), + self.user_fee_increase(), + ), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + vec![SignatureError::InvalidSignaturePublicKeySecurityLevelError( + InvalidSignaturePublicKeySecurityLevelError::new( + signing_key.security_level(), + security_levels, + ), + ) + .into()], + )); + } + + // We should validate that all newly created documents have valid ids + for transition in self.transitions_iter() { + if let BatchedTransitionRef::Document(DocumentTransition::Create(create_transition)) = + transition + { + // Validate the ID + let generated_document_id = Document::generate_document_id_v0( + create_transition.base().data_contract_id_ref(), + &self.owner_id(), + create_transition.base().document_type_name(), + &create_transition.entropy(), + ); + + // This hash will take 2 blocks (128 bytes) + execution_context.add_operation(ValidationOperation::DoubleSha256(2)); + + let id = create_transition.base().id(); + if generated_document_id != id { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition( + create_transition.base(), + self.owner_id(), + self.user_fee_increase(), + ), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + vec![ + InvalidDocumentTransitionIdError::new(generated_document_id, id).into(), + ], + )); + } + } + } + + // Next we need to validate the structure of all actions (this means with the data contract) + for transition in action.transitions() { + match transition { + BatchedTransitionAction::DocumentAction(document_action) => match document_action { + DocumentTransitionAction::CreateAction(create_action) => { + let result = create_action.validate_structure( + identity.id, + block_info, + network, + platform_version, + )?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(document_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + DocumentTransitionAction::ReplaceAction(replace_action) => { + let result = replace_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(replace_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + DocumentTransitionAction::DeleteAction(delete_action) => { + let result = delete_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(delete_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + DocumentTransitionAction::TransferAction(transfer_action) => { + let result = transfer_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transfer_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + DocumentTransitionAction::UpdatePriceAction(update_price_action) => { + let result = update_price_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(update_price_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + DocumentTransitionAction::PurchaseAction(purchase_action) => { + let result = purchase_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(purchase_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + }, + BatchedTransitionAction::TokenAction(token_action) => match token_action { + TokenTransitionAction::BurnAction(burn_action) => { + let result = burn_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(token_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::MintAction(mint_action) => { + let result = mint_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(mint_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::TransferAction(transfer_action) => { + let result = transfer_action + .validate_structure(self.owner_id(), platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(transfer_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::FreezeAction(freeze_action) => { + let result = freeze_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(freeze_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::UnfreezeAction(unfreeze_action) => { + let result = unfreeze_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(unfreeze_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::EmergencyActionAction(emergency_action_action) => { + let result = + emergency_action_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action(emergency_action_action.base(), self.owner_id(), self.user_fee_increase()), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + result.errors, + )); + } + } + TokenTransitionAction::DestroyFrozenFundsAction( + destroy_frozen_funds_action, + ) => { + let result = + destroy_frozen_funds_action.validate_structure(platform_version)?; + if !result.is_valid() { + let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( + 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, + )); + } + } + }, + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { + return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "we should not have a bump identity contract nonce at this stage", + ))); + } + } + } + Ok(ConsensusValidationResult::new()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/balance/mod.rs similarity index 76% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/balance/mod.rs index b56c2b8ff3..2b46fb6624 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/balance/mod.rs @@ -1,14 +1,14 @@ use crate::error::execution::ExecutionError; use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::balance::v0::DocumentsBatchTransitionBalanceValidationV0; +use crate::execution::validation::state_transition::batch::balance::v0::DocumentsBatchTransitionBalanceValidationV0; use crate::execution::validation::state_transition::processor::v0::StateTransitionIdentityBalanceValidationV0; use dpp::identity::PartialIdentity; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::validation::SimpleConsensusValidationResult; use dpp::version::PlatformVersion; pub(crate) mod v0; -impl StateTransitionIdentityBalanceValidationV0 for DocumentsBatchTransition { +impl StateTransitionIdentityBalanceValidationV0 for BatchTransition { fn validate_minimum_balance_pre_check( &self, identity: &PartialIdentity, @@ -18,7 +18,7 @@ impl StateTransitionIdentityBalanceValidationV0 for DocumentsBatchTransition { .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .balance_pre_check { 0 => self.validate_advanced_minimum_balance_pre_check_v0(identity, platform_version), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/balance/v0/mod.rs similarity index 89% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/balance/v0/mod.rs index 6f2dc0fd99..63b5472314 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/balance/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/balance/v0/mod.rs @@ -4,12 +4,11 @@ use dpp::consensus::basic::BasicError; use dpp::consensus::state::identity::IdentityInsufficientBalanceError; use dpp::consensus::ConsensusError; use dpp::identity::PartialIdentity; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; -use dpp::ProtocolError; - +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::validation::SimpleConsensusValidationResult; +use dpp::ProtocolError; use crate::error::execution::ExecutionError; use dpp::version::PlatformVersion; @@ -23,7 +22,7 @@ pub(in crate::execution::validation::state_transition::state_transitions) trait ) -> Result; } -impl DocumentsBatchTransitionBalanceValidationV0 for DocumentsBatchTransition { +impl DocumentsBatchTransitionBalanceValidationV0 for BatchTransition { fn validate_advanced_minimum_balance_pre_check_v0( &self, identity: &PartialIdentity, @@ -36,7 +35,7 @@ impl DocumentsBatchTransitionBalanceValidationV0 for DocumentsBatchTransition { "expected to have a balance on identity for documents batch transition", )))?; - let purchases_amount = match self.all_purchases_amount() { + let purchases_amount = match self.all_document_purchases_amount() { Ok(purchase_amount) => purchase_amount.unwrap_or_default(), Err(ProtocolError::Overflow(e)) => { return Ok(SimpleConsensusValidationResult::new_with_error( @@ -65,7 +64,7 @@ impl DocumentsBatchTransitionBalanceValidationV0 for DocumentsBatchTransition { Err(e) => return Err(e.into()), }; - let base_fees = match platform_version.fee_version.state_transition_min_fees.document_batch_sub_transition.checked_mul(self.transitions().len() as u64) { + let base_fees = match platform_version.fee_version.state_transition_min_fees.document_batch_sub_transition.checked_mul(self.transitions_len() as u64) { None => return Ok(SimpleConsensusValidationResult::new_with_error(ConsensusError::BasicError(BasicError::OverflowError(OverflowError::new("overflow when multiplying base fee and amount of sub transitions in documents batch transition".to_string()))))), Some(base_fees) => base_fees }; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/data_trigger_binding/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/data_trigger_binding/mod.rs similarity index 89% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/data_trigger_binding/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/data_trigger_binding/mod.rs index 6ab41f3800..9c06e6b429 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/data_trigger_binding/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/data_trigger_binding/mod.rs @@ -1,10 +1,10 @@ -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::{ DataTriggerExecutionContext, DataTriggerExecutionResult, }; use derive_more::From; use dpp::identifier::Identifier; use dpp::version::PlatformVersion; -use drive::state_transition_action::document::documents_batch::document_transition::{ +use drive::state_transition_action::batch::batched_transition::document_transition::{ DocumentTransitionAction, DocumentTransitionActionType, }; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/data_trigger_binding/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/data_trigger_binding/v0/mod.rs similarity index 96% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/data_trigger_binding/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/data_trigger_binding/v0/mod.rs index 7c390af6f2..39e3c871c6 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/data_trigger_binding/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/data_trigger_binding/v0/mod.rs @@ -1,10 +1,10 @@ use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::{ DataTrigger, DataTriggerExecutionContext, DataTriggerExecutionResult, }; use dpp::identifier::Identifier; use dpp::version::PlatformVersion; -use drive::state_transition_action::document::documents_batch::document_transition::{ +use drive::state_transition_action::batch::batched_transition::document_transition::{ DocumentTransitionAction, DocumentTransitionActionType, }; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/list/mod.rs similarity index 79% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/list/mod.rs index ea2bdcc07a..52c0d8c55b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/list/mod.rs @@ -1,6 +1,6 @@ use dpp::ProtocolError; use dpp::version::PlatformVersion; -use crate::execution::validation::state_transition::documents_batch::data_triggers::bindings::data_trigger_binding::DataTriggerBinding; +use crate::execution::validation::state_transition::batch::data_triggers::bindings::data_trigger_binding::DataTriggerBinding; mod v0; @@ -11,7 +11,7 @@ pub fn data_trigger_bindings_list( .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .data_triggers .bindings { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/list/v0/mod.rs similarity index 88% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/list/v0/mod.rs index 4e11bd50ee..fe3c94b3e4 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/list/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/list/v0/mod.rs @@ -1,13 +1,13 @@ -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::dashpay::create_contact_request_data_trigger; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::dpns::create_domain_data_trigger; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::reject::reject_data_trigger; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::withdrawals::delete_withdrawal_data_trigger; -use crate::execution::validation::state_transition::documents_batch::data_triggers::bindings::data_trigger_binding::DataTriggerBindingV0; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::dashpay::create_contact_request_data_trigger; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::dpns::create_domain_data_trigger; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::reject::reject_data_trigger; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::withdrawals::delete_withdrawal_data_trigger; +use crate::execution::validation::state_transition::batch::data_triggers::bindings::data_trigger_binding::DataTriggerBindingV0; use dpp::errors::ProtocolError; use dpp::system_data_contracts::withdrawals_contract::v1::document_types::withdrawal; use dpp::system_data_contracts::{dashpay_contract, dpns_contract, SystemDataContract}; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionActionType; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionActionType; /// Retrieves a list of data triggers binding with matching params. /// diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/bindings/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/bindings/mod.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/context.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/context.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/context.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/context.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/executor.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/executor.rs similarity index 58% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/executor.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/executor.rs index ac229976a5..a85f1b6feb 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/executor.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/executor.rs @@ -1,15 +1,14 @@ -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::{ DataTriggerExecutionContext, DataTriggerExecutionResult, }; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; -use dpp::state_transition::documents_batch_transition::document_transition::action_type::TransitionActionTypeGetter; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionTypeGetter; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use dpp::version::PlatformVersion; -use crate::execution::validation::state_transition::documents_batch::data_triggers::bindings::data_trigger_binding::DataTriggerBinding; -use crate::execution::validation::state_transition::documents_batch::data_triggers::bindings::data_trigger_binding::DataTriggerBindingV0Getters; +use crate::execution::validation::state_transition::batch::data_triggers::bindings::data_trigger_binding::DataTriggerBinding; +use crate::execution::validation::state_transition::batch::data_triggers::bindings::data_trigger_binding::DataTriggerBindingV0Getters; use crate::error::Error; -use crate::error::execution::ExecutionError; pub trait DataTriggerExecutor { fn validate_with_data_triggers( @@ -27,18 +26,8 @@ impl DataTriggerExecutor for DocumentTransitionAction { context: &DataTriggerExecutionContext, platform_version: &PlatformVersion, ) -> Result { - let data_contract_id = self - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .data_contract_id(); - let document_type_name = self - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .document_type_name(); + let data_contract_id = self.base().data_contract_id(); + let document_type_name = self.base().document_type_name(); let transition_action = self.action_type(); // Match data triggers by action type, contract ID and document type name diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/mod.rs similarity index 94% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/mod.rs index 9920418f53..21bdb91774 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/mod.rs @@ -2,7 +2,7 @@ use dpp::validation::SimpleValidationResult; /// Data triggers implement custom validation logic for state transitions /// that modifies documents in a specific data contract. /// Data triggers can be assigned based on the data contract ID, document type, and action. -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use crate::error::Error; use dpp::consensus::state::data_trigger::DataTriggerError; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dashpay/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/mod.rs similarity index 74% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dashpay/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/mod.rs index 1f2e7fbbf8..61c486c13a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dashpay/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/mod.rs @@ -1,11 +1,11 @@ use crate::error::execution::ExecutionError; use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::triggers::dashpay::v0::create_contact_request_data_trigger_v0; +use crate::execution::validation::state_transition::batch::data_triggers::{ DataTriggerExecutionContext, DataTriggerExecutionResult, }; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; use dpp::version::PlatformVersion; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::dashpay::v0::create_contact_request_data_trigger_v0; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; mod v0; @@ -18,7 +18,7 @@ pub fn create_contact_request_data_trigger( .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .data_triggers .triggers .create_contact_request_data_trigger diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dashpay/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs similarity index 86% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dashpay/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs index b1b183ef24..d3cdf28513 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dashpay/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay/v0/mod.rs @@ -6,14 +6,14 @@ use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; use dpp::ProtocolError; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; use dpp::system_data_contracts::dashpay_contract::v1::document_types::contact_request::properties ::{TO_USER_ID}; use dpp::version::PlatformVersion; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContextMethodsV0; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; +use crate::execution::validation::state_transition::batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; /// Creates a data trigger for handling contact request documents. /// @@ -36,12 +36,7 @@ pub(super) fn create_contact_request_data_trigger_v0( context: &DataTriggerExecutionContext<'_>, platform_version: &PlatformVersion, ) -> Result { - let data_contract_fetch_info = document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .data_contract_fetch_info(); + let data_contract_fetch_info = document_transition.base().data_contract_fetch_info(); let data_contract = &data_contract_fetch_info.contract; let mut result = DataTriggerExecutionResult::default(); let is_dry_run = context.state_transition_execution_context.in_dry_run(); @@ -52,12 +47,7 @@ pub(super) fn create_contact_request_data_trigger_v0( return Err(Error::Execution(ExecutionError::DataTriggerExecutionError( format!( "the Document Transition {} isn't 'CREATE", - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base" - )))? - .id() + document_transition.base().id() ), ))); }; @@ -72,12 +62,7 @@ pub(super) fn create_contact_request_data_trigger_v0( if !is_dry_run && owner_id == &to_user_id { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!("Identity {to_user_id} must not be equal to owner id"), ); @@ -120,14 +105,15 @@ mod test { use dpp::document::{DocumentV0Getters, DocumentV0Setters}; use dpp::platform_value; use dpp::platform_value::{Bytes32}; - use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionAction; - use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionActionType; - use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::dashpay::create_contact_request_data_trigger; + use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionAction; + use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionActionType; + use crate::execution::validation::state_transition::batch::data_triggers::triggers::dashpay::create_contact_request_data_trigger; use crate::platform_types::platform::PlatformStateRef; use crate::test::helpers::setup::TestPlatformBuilder; use super::*; use dpp::errors::consensus::state::data_trigger::DataTriggerError; - use dpp::tests::fixtures::{get_contact_request_document_fixture, get_dashpay_contract_fixture, get_document_transitions_fixture, get_identity_fixture}; + use dpp::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; + use dpp::tests::fixtures::{get_contact_request_document_fixture, get_dashpay_contract_fixture, get_batched_transitions_fixture, get_identity_fixture}; use dpp::version::DefaultForPlatformVersion; use drive::drive::contract::DataContractFetchInfo; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; @@ -165,7 +151,7 @@ mod test { .document_type_for_name("contactRequest") .expect("expected a contact request"); - let document_transitions = get_document_transitions_fixture( + let document_transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, vec![(contact_request_document, document_type, Bytes32::default())], @@ -194,7 +180,7 @@ mod test { }; let result = create_contact_request_data_trigger( - &DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { Ok(Arc::new(DataContractFetchInfo::dashpay_contract_fixture(protocol_version))) }, platform_version).expect("expected to create action").0.into(), &data_trigger_context, @@ -268,7 +254,7 @@ mod test { .document_type_for_name("contactRequest") .expect("expected a contact request"); - let document_transitions = get_document_transitions_fixture( + let document_transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, vec![(contact_request_document, document_type, Bytes32::default())], @@ -312,7 +298,7 @@ mod test { let _dashpay_identity_id = data_trigger_context.owner_id.to_owned(); let result = create_contact_request_data_trigger( - &DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { Ok(Arc::new(DataContractFetchInfo::dashpay_contract_fixture(protocol_version))) }, platform_version).expect("expected to create action").0.into(), &data_trigger_context, @@ -396,7 +382,7 @@ mod test { .get_identifier("toUserId") .expect("expected to get toUserId"); - let document_transitions = get_document_transitions_fixture( + let document_transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, vec![(contact_request_document, document_type, Bytes32::default())], @@ -425,7 +411,7 @@ mod test { let _dashpay_identity_id = data_trigger_context.owner_id.to_owned(); let result = create_contact_request_data_trigger( - &DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, document_create_transition, &BlockInfo::default(), |_identifier| { Ok(Arc::new(DataContractFetchInfo::dashpay_contract_fixture(protocol_version))) }, platform_version).expect("expected to create action").0.into(), &data_trigger_context, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dpns/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/mod.rs similarity index 70% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dpns/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/mod.rs index efd55c380f..42159810dd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dpns/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/mod.rs @@ -1,9 +1,11 @@ -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use dpp::version::PlatformVersion; -use crate::error::Error; use crate::error::execution::ExecutionError; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::dpns::v0::create_domain_data_trigger_v0; +use crate::error::Error; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::dpns::v0::create_domain_data_trigger_v0; +use crate::execution::validation::state_transition::batch::data_triggers::{ + DataTriggerExecutionContext, DataTriggerExecutionResult, +}; +use dpp::version::PlatformVersion; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; mod v0; @@ -16,7 +18,7 @@ pub fn create_domain_data_trigger( .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .data_triggers .triggers .create_domain_data_trigger diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dpns/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs similarity index 79% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dpns/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs index a790d727bd..55ffa74672 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/dpns/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs @@ -8,16 +8,16 @@ use std::collections::BTreeMap; use crate::error::execution::ExecutionError; use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::{ DataTriggerExecutionContext, DataTriggerExecutionResult, }; use dpp::document::DocumentV0Getters; use dpp::platform_value::btreemap_extensions::{BTreeValueMapHelper, BTreeValueMapPathHelper}; use dpp::platform_value::Value; use dpp::ProtocolError; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use dpp::system_data_contracts::dpns_contract; use dpp::system_data_contracts::dpns_contract::v1::document_types::domain::properties::{ALLOW_SUBDOMAINS, DASH_ALIAS_IDENTITY_ID, DASH_UNIQUE_IDENTITY_ID, LABEL, NORMALIZED_LABEL, NORMALIZED_PARENT_DOMAIN_NAME, PREORDER_SALT, RECORDS}; @@ -50,12 +50,7 @@ pub(super) fn create_domain_data_trigger_v0( context: &DataTriggerExecutionContext<'_>, platform_version: &PlatformVersion, ) -> Result { - let data_contract_fetch_info = document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .data_contract_fetch_info(); + let data_contract_fetch_info = document_transition.base().data_contract_fetch_info(); let data_contract = &data_contract_fetch_info.contract; let is_dry_run = context.state_transition_execution_context.in_dry_run(); let document_create_transition = match document_transition { @@ -64,12 +59,7 @@ pub(super) fn create_domain_data_trigger_v0( return Err(Error::Execution(ExecutionError::DataTriggerExecutionError( format!( "the Document Transition {} isn't 'CREATE", - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base" - )))? - .id() + document_transition.base().id() ), ))) } @@ -118,12 +108,7 @@ pub(super) fn create_domain_data_trigger_v0( if full_domain_name.len() > MAX_PRINTABLE_DOMAIN_NAME_LENGTH { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!( "Full domain name length can not be more than {} characters long but got {}", MAX_PRINTABLE_DOMAIN_NAME_LENGTH, @@ -137,12 +122,7 @@ pub(super) fn create_domain_data_trigger_v0( if normalized_label != convert_to_homograph_safe_chars(label.as_str()) { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!( "Normalized label doesn't match label: {} != {}", normalized_label, label @@ -157,12 +137,7 @@ pub(super) fn create_domain_data_trigger_v0( { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!( "Normalized parent domain name doesn't match parent domain name: {} != {}", normalized_parent_domain_name, parent_domain_name @@ -179,12 +154,7 @@ pub(super) fn create_domain_data_trigger_v0( if id != owner_id { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!( "ownerId {} doesn't match {} {}", owner_id, DASH_UNIQUE_IDENTITY_ID, id @@ -202,12 +172,7 @@ pub(super) fn create_domain_data_trigger_v0( if id != owner_id { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!( "ownerId {} doesn't match {} {}", owner_id, DASH_ALIAS_IDENTITY_ID, id @@ -222,12 +187,7 @@ pub(super) fn create_domain_data_trigger_v0( { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "Can't create top level domain for this identity".to_string(), ); @@ -299,12 +259,7 @@ pub(super) fn create_domain_data_trigger_v0( if documents.is_empty() { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "Parent domain is not present".to_string(), ); @@ -317,12 +272,7 @@ pub(super) fn create_domain_data_trigger_v0( if rule_allow_subdomains { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "Allowing subdomains registration is forbidden for this domain".to_string(), ); @@ -339,12 +289,7 @@ pub(super) fn create_domain_data_trigger_v0( { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "The subdomain can be created only by the parent domain owner".to_string(), ); @@ -407,12 +352,7 @@ pub(super) fn create_domain_data_trigger_v0( if preorder_documents.is_empty() { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), format!( "preorderDocument was not found with a salted domain hash of {}", hex::encode(salted_domain_hash) @@ -429,9 +369,9 @@ mod test { use std::sync::Arc; use dpp::block::block_info::BlockInfo; use dpp::platform_value::Bytes32; - use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionAction; - use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionActionType; - use dpp::tests::fixtures::{get_document_transitions_fixture, get_dpns_data_contract_fixture, get_dpns_parent_document_fixture, ParentDocumentOptions}; + use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionAction; + use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionActionType; + use dpp::tests::fixtures::{get_batched_transitions_fixture, get_dpns_data_contract_fixture, get_dpns_parent_document_fixture, ParentDocumentOptions}; use dpp::tests::utils::generate_random_identifier_struct; use dpp::version::{DefaultForPlatformVersion}; use drive::drive::contract::DataContractFetchInfo; @@ -440,6 +380,7 @@ mod test { use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::test::helpers::setup::TestPlatformBuilder; use super::*; + use dpp::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; #[test] fn should_return_execution_result_on_dry_run() { @@ -481,7 +422,7 @@ mod test { let document_type = data_contract .document_type_for_name("domain") .expect("expected to get domain document type"); - let transitions = get_document_transitions_fixture( + let transitions = get_batched_transitions_fixture( [( DocumentTransitionActionType::Create, vec![(document, document_type, Bytes32::default())], @@ -504,8 +445,8 @@ mod test { }; let result = create_domain_data_trigger_v0( - &DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, - document_create_transition, &BlockInfo::default(), |_identifier| { + &DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(&platform.drive, None, + document_create_transition, &BlockInfo::default(), |_identifier| { Ok(Arc::new(DataContractFetchInfo::dpns_contract_fixture(platform_version.protocol_version))) }, platform_version).expect("expected to create action").0.into(), &data_trigger_context, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/feature_flags/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/feature_flags/mod.rs similarity index 70% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/feature_flags/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/feature_flags/mod.rs index 9b0ecd6187..31f4b43ccb 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/feature_flags/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/feature_flags/mod.rs @@ -1,9 +1,9 @@ -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use dpp::version::PlatformVersion; use crate::error::Error; use crate::error::execution::ExecutionError; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::feature_flags::v0::create_feature_flag_data_trigger_v0; +use crate::execution::validation::state_transition::batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::feature_flags::v0::create_feature_flag_data_trigger_v0; mod v0; @@ -17,7 +17,7 @@ pub fn create_feature_flag_data_trigger( .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .data_triggers .triggers .create_feature_flag_data_trigger diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/feature_flags/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/feature_flags/v0/mod.rs similarity index 83% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/feature_flags/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/feature_flags/v0/mod.rs index 50c867efa6..d1cca4bf1a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/feature_flags/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/feature_flags/v0/mod.rs @@ -6,9 +6,9 @@ use dpp::consensus::state::data_trigger::data_trigger_condition_error::DataTrigg use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use dpp::system_data_contracts::feature_flags_contract; use dpp::system_data_contracts::feature_flags_contract::v1::document_types::update_consensus_params::properties ::PROPERTY_ENABLE_AT_HEIGHT; @@ -39,12 +39,7 @@ pub(super) fn create_feature_flag_data_trigger_v0( _platform_version: &PlatformVersion, ) -> Result { let mut result = DataTriggerExecutionResult::default(); - let data_contract_fetch_info = document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .data_contract_fetch_info(); + let data_contract_fetch_info = document_transition.base().data_contract_fetch_info(); let data_contract = &data_contract_fetch_info.contract; let document_create_transition = match document_transition { @@ -53,12 +48,7 @@ pub(super) fn create_feature_flag_data_trigger_v0( return Err(Error::Execution(ExecutionError::DataTriggerExecutionError( format!( "the Document Transition {} isn't 'CREATE", - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base" - )))? - .id() + document_transition.base().id() ), ))) } @@ -78,12 +68,7 @@ pub(super) fn create_feature_flag_data_trigger_v0( if enable_at_height < latest_block_height { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "This identity can't activate selected feature flag".to_string(), ); @@ -95,12 +80,7 @@ pub(super) fn create_feature_flag_data_trigger_v0( if context.owner_id != &feature_flags_contract::OWNER_ID { let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "This identity can't activate selected feature flag".to_string(), ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/mod.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/reject/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/reject/mod.rs similarity index 69% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/reject/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/reject/mod.rs index 402668738d..7c540836ca 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/reject/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/reject/mod.rs @@ -1,9 +1,11 @@ -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use dpp::version::PlatformVersion; -use crate::error::Error; use crate::error::execution::ExecutionError; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::reject::v0::reject_data_trigger_v0; +use crate::error::Error; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::reject::v0::reject_data_trigger_v0; +use crate::execution::validation::state_transition::batch::data_triggers::{ + DataTriggerExecutionContext, DataTriggerExecutionResult, +}; +use dpp::version::PlatformVersion; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; mod v0; @@ -16,7 +18,7 @@ pub fn reject_data_trigger( .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .data_triggers .triggers .reject_data_trigger diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/reject/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/reject/v0/mod.rs similarity index 68% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/reject/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/reject/v0/mod.rs index 69c287e600..1fe229182f 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/reject/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/reject/v0/mod.rs @@ -1,10 +1,9 @@ use dpp::consensus::state::data_trigger::data_trigger_condition_error::DataTriggerConditionError; use dpp::data_contract::accessors::v0::DataContractV0Getters; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::data_triggers::DataTriggerExecutionResult; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use crate::error::execution::ExecutionError; +use crate::execution::validation::state_transition::batch::data_triggers::DataTriggerExecutionResult; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; /// Creates a data trigger for handling document rejections. /// @@ -26,23 +25,13 @@ use crate::error::execution::ExecutionError; pub(super) fn reject_data_trigger_v0( document_transition: &DocumentTransitionAction, ) -> Result { - let data_contract_fetch_info = document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .data_contract_fetch_info(); + let data_contract_fetch_info = document_transition.base().data_contract_fetch_info(); let data_contract = &data_contract_fetch_info.contract; let mut result = DataTriggerExecutionResult::default(); let err = DataTriggerConditionError::new( data_contract.id(), - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .id(), + document_transition.base().id(), "Action is not allowed".to_string(), ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/withdrawals/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/mod.rs similarity index 74% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/withdrawals/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/mod.rs index ae8758fe06..967adaba8c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/withdrawals/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/mod.rs @@ -1,11 +1,11 @@ use crate::error::execution::ExecutionError; use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::{ DataTriggerExecutionContext, DataTriggerExecutionResult, }; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use dpp::version::PlatformVersion; -use crate::execution::validation::state_transition::documents_batch::data_triggers::triggers::withdrawals::v0::delete_withdrawal_data_trigger_v0; +use crate::execution::validation::state_transition::batch::data_triggers::triggers::withdrawals::v0::delete_withdrawal_data_trigger_v0; mod v0; @@ -18,7 +18,7 @@ pub fn delete_withdrawal_data_trigger( .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .data_triggers .triggers .delete_withdrawal_data_trigger diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/withdrawals/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs similarity index 91% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/withdrawals/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs index e0960ea715..e39046a670 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/data_triggers/triggers/withdrawals/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs @@ -4,7 +4,7 @@ use crate::error::Error; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; use dpp::platform_value::Value; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use dpp::system_data_contracts::withdrawals_contract; use dpp::version::PlatformVersion; use drive::query::{DriveDocumentQuery, InternalClauses, WhereClause, WhereOperator}; @@ -13,11 +13,11 @@ use dpp::consensus::state::data_trigger::data_trigger_condition_error::DataTrigg use dpp::{document, ProtocolError}; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::document::DocumentV0Getters; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; use dpp::system_data_contracts::withdrawals_contract::v1::document_types::withdrawal; use drive::drive::document::query::QueryDocumentsOutcomeV0Methods; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; +use crate::execution::validation::state_transition::batch::data_triggers::{DataTriggerExecutionContext, DataTriggerExecutionResult}; /// Creates a data trigger for handling deletion of withdrawal documents. /// @@ -39,12 +39,7 @@ pub(super) fn delete_withdrawal_data_trigger_v0( context: &DataTriggerExecutionContext<'_>, platform_version: &PlatformVersion, ) -> Result { - let data_contract_fetch_info = document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base", - )))? - .data_contract_fetch_info(); + let data_contract_fetch_info = document_transition.base().data_contract_fetch_info(); let data_contract = &data_contract_fetch_info.contract; let mut result = DataTriggerExecutionResult::default(); @@ -52,12 +47,7 @@ pub(super) fn delete_withdrawal_data_trigger_v0( return Err(Error::Execution(ExecutionError::DataTriggerExecutionError( format!( "the Document Transition {} isn't 'DELETE", - document_transition - .base() - .ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( - "expecting action to have a base" - )))? - .id() + document_transition.base().id() ), ))); }; @@ -141,9 +131,9 @@ mod tests { use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; use dpp::document::{Document, DocumentV0Getters}; use dpp::platform_value::platform_value; - use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; - use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; - use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionV0; + use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; + use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; + use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionV0; use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; use dpp::tests::fixtures::{get_data_contract_fixture, get_withdrawal_document_fixture}; use dpp::version::PlatformVersion; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/identity_contract_nonce/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/identity_contract_nonce/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/identity_contract_nonce/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/identity_contract_nonce/mod.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/identity_contract_nonce/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/identity_contract_nonce/v0/mod.rs similarity index 82% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/identity_contract_nonce/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/identity_contract_nonce/v0/mod.rs index 1487567a4b..32829c45b7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/identity_contract_nonce/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/identity_contract_nonce/v0/mod.rs @@ -1,10 +1,9 @@ use crate::error::Error; use dpp::block::block_info::BlockInfo; use dpp::identity::identity_nonce::{validate_identity_nonce_update, validate_new_identity_nonce}; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransitionV0Methods; +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransitionLike; use dpp::validation::SimpleConsensusValidationResult; @@ -17,7 +16,7 @@ use crate::platform_types::platform::PlatformStateRef; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -pub(in crate::execution::validation::state_transition::state_transitions::documents_batch) trait DocumentsBatchStateTransitionIdentityContractNonceV0 +pub(in crate::execution::validation::state_transition::state_transitions::batch) trait DocumentsBatchStateTransitionIdentityContractNonceV0 { fn validate_identity_contract_nonces_v0( &self, @@ -29,7 +28,7 @@ pub(in crate::execution::validation::state_transition::state_transitions::docume ) -> Result; } -impl DocumentsBatchStateTransitionIdentityContractNonceV0 for DocumentsBatchTransition { +impl DocumentsBatchStateTransitionIdentityContractNonceV0 for BatchTransition { fn validate_identity_contract_nonces_v0( &self, platform: &PlatformStateRef, @@ -39,7 +38,7 @@ impl DocumentsBatchStateTransitionIdentityContractNonceV0 for DocumentsBatchTran platform_version: &PlatformVersion, ) -> Result { // We should validate that all newly created documents have valid ids - for transition in self.transitions() { + for transition in self.transitions_iter() { let revision_nonce = transition.identity_contract_nonce(); let identity_id = self.owner_id(); let (existing_nonce, fee) = platform.drive.fetch_identity_contract_nonce_with_fees( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/is_allowed/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/is_allowed/mod.rs similarity index 86% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/is_allowed/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/is_allowed/mod.rs index 8ff239d954..0e594bc589 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/is_allowed/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/is_allowed/mod.rs @@ -2,19 +2,19 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::validation::state_transition::processor::v0::StateTransitionIsAllowedValidationV0; use crate::platform_types::platform::PlatformRef; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::validation::ConsensusValidationResult; use dpp::version::PlatformVersion; mod v0; -impl StateTransitionIsAllowedValidationV0 for DocumentsBatchTransition { +impl StateTransitionIsAllowedValidationV0 for BatchTransition { fn has_is_allowed_validation(&self, platform_version: &PlatformVersion) -> Result { match platform_version .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .is_allowed { 0 => Ok(true), @@ -36,7 +36,7 @@ impl StateTransitionIsAllowedValidationV0 for DocumentsBatchTransition { .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .is_allowed { 0 => Ok(v0::validate_is_allowed_v0(self, platform)), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/is_allowed/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/is_allowed/v0/mod.rs similarity index 75% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/is_allowed/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/is_allowed/v0/mod.rs index a98801ee70..82f7855f1c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/is_allowed/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/is_allowed/v0/mod.rs @@ -2,9 +2,10 @@ use crate::platform_types::platform::PlatformRef; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use dpp::block::epoch::EpochIndex; use dpp::consensus::basic::document::ContestedDocumentsTemporarilyNotAllowedError; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use dpp::state_transition::batch_transition::resolvers::v0::BatchTransitionResolversV0; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::validation::ConsensusValidationResult; // TARGET_EPOCH_INDEX was introduced without versioning. @@ -15,7 +16,7 @@ pub const TARGET_EPOCH_INDEX: EpochIndex = 4; #[inline(always)] pub fn validate_is_allowed_v0( - state_transition: &DocumentsBatchTransition, + state_transition: &BatchTransition, platform: &PlatformRef, ) -> ConsensusValidationResult<()> { #[cfg(feature = "testing-config")] @@ -33,7 +34,7 @@ pub fn validate_is_allowed_v0( return ConsensusValidationResult::new(); } - let is_contested = state_transition.transitions().iter().any(|transition| { + let is_contested = state_transition.transitions_iter().any(|transition| { transition .as_transition_create() .and_then(|create| create.prefunded_voting_balance().as_ref()) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs similarity index 66% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs index e5ee8b9919..83ac4eb0f6 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/mod.rs @@ -11,7 +11,7 @@ use dpp::block::block_info::BlockInfo; use dpp::dashcore::Network; use dpp::identity::PartialIdentity; use dpp::prelude::*; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::validation::SimpleConsensusValidationResult; use dpp::version::PlatformVersion; use drive::state_transition_action::StateTransitionAction; @@ -25,9 +25,9 @@ use crate::execution::types::state_transition_execution_context::StateTransition use crate::platform_types::platform::{PlatformRef, PlatformStateRef}; use crate::rpc::core::CoreRPCLike; -use crate::execution::validation::state_transition::documents_batch::advanced_structure::v0::DocumentsBatchStateTransitionStructureValidationV0; -use crate::execution::validation::state_transition::documents_batch::identity_contract_nonce::v0::DocumentsBatchStateTransitionIdentityContractNonceV0; -use crate::execution::validation::state_transition::documents_batch::state::v0::DocumentsBatchStateTransitionStateValidationV0; +use crate::execution::validation::state_transition::batch::advanced_structure::v0::DocumentsBatchStateTransitionStructureValidationV0; +use crate::execution::validation::state_transition::batch::identity_contract_nonce::v0::DocumentsBatchStateTransitionIdentityContractNonceV0; +use crate::execution::validation::state_transition::batch::state::v0::DocumentsBatchStateTransitionStateValidationV0; use crate::execution::validation::state_transition::processor::v0::{ StateTransitionBasicStructureValidationV0, StateTransitionNonceValidationV0, @@ -38,8 +38,8 @@ use crate::execution::validation::state_transition::ValidationMode; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; impl ValidationMode { - /// Returns a bool on whether we should validate that documents are valid against the state - pub fn should_validate_document_valid_against_state(&self) -> bool { + /// Returns a bool on whether we should validate that batched transitions are valid against the state + pub fn should_validate_batch_valid_against_state(&self) -> bool { match self { ValidationMode::CheckTx => false, ValidationMode::RecheckTx => false, @@ -49,7 +49,7 @@ impl ValidationMode { } } -impl StateTransitionActionTransformerV0 for DocumentsBatchTransition { +impl StateTransitionActionTransformerV0 for BatchTransition { fn transform_into_action( &self, platform: &PlatformRef, @@ -64,7 +64,7 @@ impl StateTransitionActionTransformerV0 for DocumentsBatchTransition { .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .transform_into_action { 0 => self.transform_into_action_v0(&platform.into(), block_info, validation_mode, tx), @@ -77,7 +77,7 @@ impl StateTransitionActionTransformerV0 for DocumentsBatchTransition { } } -impl StateTransitionBasicStructureValidationV0 for DocumentsBatchTransition { +impl StateTransitionBasicStructureValidationV0 for BatchTransition { fn validate_basic_structure( &self, platform_version: &PlatformVersion, @@ -86,7 +86,7 @@ impl StateTransitionBasicStructureValidationV0 for DocumentsBatchTransition { .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .basic_structure { 0 => { @@ -103,7 +103,7 @@ impl StateTransitionBasicStructureValidationV0 for DocumentsBatchTransition { } } -impl StateTransitionNonceValidationV0 for DocumentsBatchTransition { +impl StateTransitionNonceValidationV0 for BatchTransition { fn validate_nonces( &self, platform: &PlatformStateRef, @@ -116,7 +116,7 @@ impl StateTransitionNonceValidationV0 for DocumentsBatchTransition { .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .revision { 0 => self.validate_identity_contract_nonces_v0( @@ -135,7 +135,7 @@ impl StateTransitionNonceValidationV0 for DocumentsBatchTransition { } } -impl StateTransitionStructureKnownInStateValidationV0 for DocumentsBatchTransition { +impl StateTransitionStructureKnownInStateValidationV0 for BatchTransition { fn validate_advanced_structure_from_state( &self, block_info: &BlockInfo, @@ -149,7 +149,7 @@ impl StateTransitionStructureKnownInStateValidationV0 for DocumentsBatchTransiti .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .advanced_structure { 0 => { @@ -157,8 +157,7 @@ impl StateTransitionStructureKnownInStateValidationV0 for DocumentsBatchTransiti identity.ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( "The identity must be known on advanced structure validation", )))?; - let StateTransitionAction::DocumentsBatchAction(documents_batch_transition_action) = - action + let StateTransitionAction::BatchAction(documents_batch_transition_action) = action else { return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( "action must be a documents batch transition action", @@ -190,7 +189,7 @@ impl StateTransitionStructureKnownInStateValidationV0 for DocumentsBatchTransiti } } -impl StateTransitionStateValidationV0 for DocumentsBatchTransition { +impl StateTransitionStateValidationV0 for BatchTransition { fn validate_state( &self, action: Option, @@ -206,7 +205,7 @@ impl StateTransitionStateValidationV0 for DocumentsBatchTransition { .drive_abci .validation_and_processing .state_transitions - .documents_batch_state_transition + .batch_state_transition .state { 0 => { @@ -214,8 +213,7 @@ impl StateTransitionStateValidationV0 for DocumentsBatchTransition { action.ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution( "documents batch structure validation should have an action", )))?; - let StateTransitionAction::DocumentsBatchAction(documents_batch_transition_action) = - action + let StateTransitionAction::BatchAction(documents_batch_transition_action) = action else { return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( "action must be a documents batch transition action", @@ -245,7 +243,11 @@ mod tests { use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; use dpp::block::block_info::BlockInfo; + use dpp::consensus::basic::BasicError; + use dpp::consensus::state::state_error::StateError; + use dpp::consensus::ConsensusError; use dpp::dash_to_credits; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; @@ -257,13 +259,14 @@ mod tests { use dpp::document::{DocumentV0Getters, DocumentV0Setters}; use dpp::fee::fee_result::BalanceChange; use dpp::fee::Credits; + use dpp::identifier::Identifier; use dpp::identity::accessors::IdentityGettersV0; use dpp::nft::TradeMode; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; use dpp::platform_value::{Bytes32, Value}; use dpp::serialization::PlatformSerializable; - use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; - use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; + use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; + use dpp::state_transition::batch_transition::BatchTransition; use dpp::tests::json_document::json_document_to_contract; use drive::drive::document::query::QueryDocumentsOutcomeV0Methods; use drive::drive::document::query::QueryDocumentsWithFlagsOutcomeV0Methods; @@ -271,10 +274,10 @@ mod tests { use drive::util::storage_flags::StorageFlags; use platform_version::version::PlatformVersion; use rand::prelude::StdRng; + use rand::Rng; use rand::SeedableRng; mod creation_tests { - use rand::Rng; use dapi_grpc::platform::v0::{get_contested_resource_vote_state_request, get_contested_resource_vote_state_response, GetContestedResourceVoteStateRequest, GetContestedResourceVoteStateResponse}; use dapi_grpc::platform::v0::get_contested_resource_vote_state_request::get_contested_resource_vote_state_request_v0::ResultType; use dapi_grpc::platform::v0::get_contested_resource_vote_state_request::GetContestedResourceVoteStateRequestV0; @@ -306,10 +309,11 @@ mod tests { use dpp::consensus::state::state_error::StateError; use dpp::dashcore::Network; use dpp::dashcore::Network::Testnet; + use dpp::data_contract::DataContract; use dpp::identity::SecurityLevel; - use dpp::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; - use dpp::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransitionV0; - use dpp::state_transition::documents_batch_transition::{DocumentCreateTransition, DocumentsBatchTransitionV0}; + use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; + use dpp::state_transition::batch_transition::document_create_transition::DocumentCreateTransitionV0; + use dpp::state_transition::batch_transition::{DocumentCreateTransition, BatchTransitionV0}; use dpp::state_transition::StateTransition; use crate::config::PlatformConfig; @@ -352,7 +356,7 @@ mod tests { document.set("avatarUrl", "http://test.com/bob.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -438,7 +442,7 @@ mod tests { document.set("avatarUrl", "http://test.com/bob.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -500,7 +504,7 @@ mod tests { document.set("avatarUrl", "http://test.com/coy.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -569,6 +573,9 @@ mod tests { "tests/supporting_files/contract/dashpay/dashpay-contract-no-max-length.json", None, None, + None::, + None, + None, ); let dashpay_contract = dashpay_contract_no_max_length.clone(); @@ -605,7 +612,7 @@ mod tests { ); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -785,7 +792,7 @@ mod tests { document_2.set("preorderSalt", salt_2.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -806,7 +813,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_2, preorder, entropy.0, @@ -827,7 +834,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1, domain, entropy.0, @@ -848,7 +855,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_2, domain, entropy.0, @@ -1208,7 +1215,7 @@ mod tests { document_1.set("preorderSalt", salt_1.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -1244,15 +1251,14 @@ mod tests { prefunded_voting_balance: None, } .into(); - let documents_batch_inner_create_transition_1: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id, - transitions: vec![create_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 0, - signature: Default::default(), - } - .into(); + let documents_batch_inner_create_transition_1: BatchTransition = BatchTransitionV0 { + owner_id, + transitions: vec![create_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); let mut documents_batch_create_transition_1: StateTransition = documents_batch_inner_create_transition_1.into(); documents_batch_create_transition_1 @@ -1486,7 +1492,7 @@ mod tests { document_1.set("preorderSalt", salt_1.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -1521,15 +1527,14 @@ mod tests { prefunded_voting_balance: None, } .into(); - let documents_batch_inner_create_transition_1: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id, - transitions: vec![create_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 0, - signature: Default::default(), - } - .into(); + let documents_batch_inner_create_transition_1: BatchTransition = BatchTransitionV0 { + owner_id, + transitions: vec![create_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); let mut documents_batch_create_transition_1: StateTransition = documents_batch_inner_create_transition_1.into(); documents_batch_create_transition_1 @@ -1838,7 +1843,7 @@ mod tests { document_3_on_identity_1.set("preorderSalt", salt_3.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -1859,7 +1864,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_2, preorder, entropy.0, @@ -1880,7 +1885,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_3 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_3_on_identity_1, preorder, new_entropy.0, @@ -1901,7 +1906,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1, domain, entropy.0, @@ -1922,7 +1927,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_2, domain, entropy.0, @@ -1943,7 +1948,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_3 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_3_on_identity_1, domain, entropy.0, @@ -2383,7 +2388,7 @@ mod tests { )); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1, domain, different_entropy.0, @@ -2616,7 +2621,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -2678,7 +2683,7 @@ mod tests { document.set("defense", 2.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -2787,7 +2792,7 @@ mod tests { altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -2831,7 +2836,7 @@ mod tests { .expect("expected to commit transaction"); let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, @@ -2877,7 +2882,7 @@ mod tests { assert_eq!(processing_result.valid_count(), 1); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1341740); + assert_eq!(processing_result.aggregated_fees().processing_fee, 1443820); let issues = platform .drive @@ -2939,7 +2944,7 @@ mod tests { document.set("avatarUrl", "http://test.com/bob.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), profile, entropy.0, @@ -2996,7 +3001,7 @@ mod tests { ); //less than a week let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( document.clone(), profile, &key, @@ -3286,7 +3291,7 @@ mod tests { altered_document.set("senderKeyIndex", Value::U32(2)); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, contact_request_document_type, entropy.0, @@ -3330,7 +3335,7 @@ mod tests { .expect("expected to commit transaction"); let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, contact_request_document_type, &key, @@ -3416,7 +3421,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -3512,7 +3517,7 @@ mod tests { document.set("defense", 0.into()); let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( document, card_document_type, &key, @@ -3620,7 +3625,7 @@ mod tests { altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, @@ -3722,7 +3727,7 @@ mod tests { altered_document_2.set("avatarUrl", "http://test.com/drapes.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -3787,7 +3792,7 @@ mod tests { assert_eq!(document.to_string(), "v0 : id:GcviwUsEr9Ji4rCrnnsgmVAghNaVPDumsfcagvBbBy45 owner_id:CisQdz2ej7EwWv8JbetSXBNsV4xsf8QsSS8tqp4tEf7V created_at:1970-01-14 21:20:00 updated_at:1970-01-14 21:20:00 avatarFingerprint:bytes d7b0e2b357c10312 avatarHash:bytes32 YonaRoE0hMgat53AYt5LTlQlIkKLReGpB7xNAqJ5HM8= avatarUrl:string http://test.com/bob.[...(23)] displayName:string QBwBNNXXYCngB0er publicMessage:string 8XG7KBGNvm2 "); let documents_batch_update_transition_1 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, @@ -3807,7 +3812,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_update_transition_2 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document_2, profile, &key, @@ -3940,7 +3945,7 @@ mod tests { altered_document_2.set("avatarUrl", "http://test.com/drapes.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -4009,7 +4014,7 @@ mod tests { let platform_state = platform.state.load(); let documents_batch_update_transition_1 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, @@ -4029,7 +4034,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_update_transition_2 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document_2, profile, &key, @@ -4199,7 +4204,7 @@ mod tests { altered_document_2.increment_revision().unwrap(); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -4268,7 +4273,7 @@ mod tests { let platform_state = platform.state.load(); let documents_batch_update_transition_1 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, @@ -4288,7 +4293,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_update_transition_2 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document_2, profile, &key, @@ -4462,7 +4467,7 @@ mod tests { altered_document_2.set("avatarUrl", "http://test.com/drapes.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -4531,7 +4536,7 @@ mod tests { let platform_state = platform.state.load(); let documents_batch_update_transition_1 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document, profile, &key, @@ -4551,7 +4556,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_update_transition_2 = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( altered_document_2, profile, &key, @@ -4723,7 +4728,7 @@ mod tests { altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, profile, entropy.0, @@ -4767,7 +4772,7 @@ mod tests { .expect("expected to commit transaction"); let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( altered_document, profile, &key, @@ -4813,7 +4818,7 @@ mod tests { assert_eq!(processing_result.valid_count(), 1); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1609340); + assert_eq!(processing_result.aggregated_fees().processing_fee, 1711420); let issues = platform .drive @@ -4904,7 +4909,7 @@ mod tests { altered_document.set("senderKeyIndex", Value::U32(2)); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, contact_request_document_type, entropy.0, @@ -4948,7 +4953,7 @@ mod tests { .expect("expected to commit transaction"); let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( altered_document, contact_request_document_type, &key, @@ -5069,7 +5074,7 @@ mod tests { altered_document.set("senderKeyIndex", Value::U32(2)); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, contact_request_document_type, entropy.0, @@ -5113,7 +5118,7 @@ mod tests { .expect("expected to commit transaction"); let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( altered_document, contact_request_document_type, &key, @@ -5234,7 +5239,7 @@ mod tests { altered_document.set("senderKeyIndex", Value::U32(2)); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document, contact_request_document_type, entropy.0, @@ -5278,7 +5283,7 @@ mod tests { .expect("expected to commit transaction"); let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( altered_document, contact_request_document_type, &key, @@ -5371,7 +5376,7 @@ mod tests { altered_document.set("avatarUrl", "http://test.com/cat.jpg".into()); let documents_batch_delete_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( altered_document, profile, &key, @@ -5484,7 +5489,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -5530,7 +5535,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( + BatchTransition::new_document_transfer_transition_from_document( document, card_document_type, receiver.id(), @@ -5639,7 +5644,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -5732,7 +5737,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( + BatchTransition::new_document_transfer_transition_from_document( document, card_document_type, receiver.id(), @@ -5864,7 +5869,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -5957,7 +5962,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( + BatchTransition::new_document_transfer_transition_from_document( document, card_document_type, receiver.id(), @@ -6109,7 +6114,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( + BatchTransition::new_document_transfer_transition_from_document( document, card_document_type, receiver.id(), @@ -6215,7 +6220,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -6308,7 +6313,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_transfer_transition = - DocumentsBatchTransition::new_document_transfer_transition_from_document( + BatchTransition::new_document_transfer_transition_from_document( document.clone(), card_document_type, receiver.id(), @@ -6378,7 +6383,7 @@ mod tests { document.set_owner_id(receiver.id()); let documents_batch_deletion_transition = - DocumentsBatchTransition::new_document_deletion_transition_from_document( + BatchTransition::new_document_deletion_transition_from_document( document, card_document_type, &recipient_key, @@ -6486,7 +6491,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -6556,7 +6561,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -6646,7 +6651,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -6739,7 +6744,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -6866,7 +6871,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -6985,7 +6990,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -7100,7 +7105,7 @@ mod tests { document.set_revision(Some(3)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, purchaser.id(), @@ -7262,7 +7267,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -7386,7 +7391,7 @@ mod tests { document.bump_revision(); let documents_batch_update_transition = - DocumentsBatchTransition::new_document_replacement_transition_from_document( + BatchTransition::new_document_replacement_transition_from_document( document.clone(), card_document_type, &key, @@ -7480,7 +7485,7 @@ mod tests { document.bump_revision(); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -7612,7 +7617,7 @@ mod tests { document.bump_revision(); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, purchaser.id(), @@ -7773,7 +7778,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -7896,7 +7901,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -8013,7 +8018,7 @@ mod tests { document.set_revision(Some(3)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, purchaser.id(), @@ -8159,7 +8164,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -8205,7 +8210,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.5), @@ -8254,7 +8259,7 @@ mod tests { document.set_revision(Some(3)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, purchaser.id(), @@ -8353,7 +8358,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -8399,7 +8404,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -8448,7 +8453,7 @@ mod tests { document.set_revision(Some(3)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, identity.id(), @@ -8552,7 +8557,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -8598,7 +8603,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -8647,7 +8652,7 @@ mod tests { document.set_revision(Some(3)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, purchaser.id(), @@ -8759,7 +8764,7 @@ mod tests { document.set_revision(Some(4)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, identity.id(), @@ -8857,7 +8862,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -8950,7 +8955,7 @@ mod tests { document.set_revision(Some(2)); let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -9043,7 +9048,7 @@ mod tests { document.set_revision(Some(3)); let documents_batch_purchase_transition = - DocumentsBatchTransition::new_document_purchase_transition_from_document( + BatchTransition::new_document_purchase_transition_from_document( document.clone(), card_document_type, receiver.id(), @@ -9137,7 +9142,7 @@ mod tests { document.set("defense", 7.into()); let documents_batch_create_transition = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document.clone(), card_document_type, entropy.0, @@ -9185,7 +9190,7 @@ mod tests { document.set_owner_id(other_identity.id()); // we do this to trick the system let documents_batch_update_price_transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( + BatchTransition::new_document_update_price_transition_from_document( document.clone(), card_document_type, dash_to_credits!(0.1), @@ -9272,15 +9277,15 @@ mod tests { use dpp::data_contract::document_type::random_document::{ DocumentFieldFillSize, DocumentFieldFillType, }; + use dpp::data_contract::DataContract; use dpp::platform_value::Bytes32; - use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; + use dpp::state_transition::batch_transition::BatchTransition; use dpp::util::hash::hash_double; use drive::query::{InternalClauses, OrderClause, WhereClause, WhereOperator}; use drive::util::test_helpers::setup_contract; use indexmap::IndexMap; use platform_version::version::PlatformVersion; use rand::prelude::StdRng; - use rand::Rng; use std::collections::BTreeMap; #[test] @@ -9309,6 +9314,9 @@ mod tests { "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", None, None, + None::, + None, + None, ); let card_game = setup_contract( @@ -9316,6 +9324,9 @@ mod tests { "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", None, None, + None::, + None, + None, ); let dpns_contract = setup_contract( @@ -9323,6 +9334,9 @@ mod tests { "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json", None, None, + None::, + None, + None, ); let preorder = dpns_contract @@ -9462,7 +9476,7 @@ mod tests { document_3.set("preorderSalt", salt_3.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -9483,7 +9497,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_2, preorder, entropy.0, @@ -9504,7 +9518,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_3 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_3, preorder, entropy.0, @@ -9525,7 +9539,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1, domain, entropy.0, @@ -9546,7 +9560,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_2, domain, entropy.0, @@ -9567,7 +9581,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_3 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_3.clone(), domain, entropy.0, @@ -9758,6 +9772,9 @@ mod tests { "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", None, None, + None::, + None, + None, ); let card_game = setup_contract( @@ -9765,6 +9782,9 @@ mod tests { "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", None, None, + None::, + None, + None, ); let dpns_contract = setup_contract( @@ -9772,6 +9792,9 @@ mod tests { "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id-null-searchable-true.json", None, None, + None::, + None, + None, ); let preorder = dpns_contract @@ -9911,7 +9934,7 @@ mod tests { document_3.set("preorderSalt", salt_3.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -9932,7 +9955,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_2, preorder, entropy.0, @@ -9953,7 +9976,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_3 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_3, preorder, entropy.0, @@ -9974,7 +9997,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1, domain, entropy.0, @@ -9995,7 +10018,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_2, domain, entropy.0, @@ -10016,7 +10039,7 @@ mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_3 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_3.clone(), domain, entropy.0, @@ -10167,4 +10190,4238 @@ mod tests { assert_eq!(documents.len(), 2); } } + + mod token_tests { + use super::*; + use crate::execution::validation::state_transition::tests::create_token_contract_with_owner_identity; + use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Setters; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + 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::state_transition::batch_transition::methods::v1::DocumentsBatchTransitionMethodsV1; + mod token_mint_tests { + use super::*; + + mod token_mint_tests_normal_scenarios { + use super::*; + + #[test] + fn test_token_mint_by_owner_allowed_sending_to_self() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(101337)); + } + + #[test] + fn test_token_mint_by_owner_allowed_sending_to_other() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (receiver, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(receiver.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + receiver.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(1337)); + } + + #[test] + fn test_token_mint_sending_to_non_existing_identity_causes_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let receiver = Identifier::random_with_rng(&mut rng); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(receiver), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::StateError( + StateError::RecipientIdentityDoesNotExistError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + receiver.to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owner_no_destination_causes_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + None, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::DestinationIdentityForTokenMintingNotSetError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + } + + mod token_mint_tests_no_recipient_minting { + use super::*; + + #[test] + fn test_token_mint_by_owned_id_allowed_sending_to_self() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_minting_allow_choosing_destination(false); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::ChoosingTokenMintRecipientNotAllowedError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + } + + #[test] + fn test_token_mint_by_owned_id_allowed_sending_to_other() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (receiver, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_minting_allow_choosing_destination(false); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(receiver.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::ChoosingTokenMintRecipientNotAllowedError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + receiver.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owned_id_no_destination_causes_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_minting_allow_choosing_destination(false); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + None, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::DestinationIdentityForTokenMintingNotSetError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + } + } + + mod token_mint_tests_contract_has_recipient { + use super::*; + + #[test] + fn test_token_mint_by_owned_id_allowed_sending_to_self() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_minting_allow_choosing_destination(false); + token_configuration + .set_new_tokens_destination_identity(Some(identity.id())); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::ChoosingTokenMintRecipientNotAllowedError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + } + + #[test] + fn test_token_mint_by_owned_id_allowed_sending_to_other() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (receiver, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_minting_allow_choosing_destination(false); + token_configuration + .set_new_tokens_destination_identity(Some(identity.id())); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(receiver.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::ChoosingTokenMintRecipientNotAllowedError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + receiver.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owned_id_no_set_destination_should_use_contracts() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_minting_allow_choosing_destination(false); + token_configuration + .set_new_tokens_destination_identity(Some(identity.id())); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + None, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(101337)); + } + } + + mod token_mint_tests_authorization_scenarios { + use super::*; + 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::group::{GroupStateTransitionInfo, GroupStateTransitionInfoStatus}; + use dpp::state_transition::batch_transition::TokenMintTransition; + + #[test] + fn test_token_mint_by_owner_sending_to_self_minting_not_allowed() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::NoOne, + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + None, + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::StateError(StateError::UnauthorizedTokenActionError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + } + + #[test] + fn test_token_mint_by_owner_sending_to_self_minting_only_allowed_by_group() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 5), (identity_2.id(), 5)].into(), + required_power: 10, + }), + )] + .into(), + ), + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::StateError(StateError::UnauthorizedTokenActionError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + } + + #[test] + fn test_token_mint_by_owner_sending_to_self_minting_only_allowed_by_group_enough_member_power( + ) { + // We are using a group, but our member alone has enough power in the group to do the action + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 5), (identity_2.id(), 1)].into(), + required_power: 5, + }), + )] + .into(), + ), + platform_version, + ); + + let documents_batch_create_transition = + BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(101337)); + } + + #[test] + fn test_token_mint_by_owner_requires_group_other_member() { + // We are using a group, and two members need to sign for the event to happen + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, signer2, key2) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + // Now we need to get the second identity to also sign it + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_2.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key2, + 2, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(101337)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owner_requires_group_resubmitting_causes_error() { + // We are using a group, and two members need to sign for the event to happen + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + // Now we need to get the second identity to also sign it, but we are going to resubmit with first + // This will create an error + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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::StateError( + StateError::GroupActionAlreadySignedByIdentityError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owner_requires_group_other_member_resubmitting_causes_error() + { + // We are using a group, and two members need to sign for the event to happen + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, signer2, key2) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_3, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_2.id(), 1), + (identity_3.id(), 1), + ] + .into(), + required_power: 3, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + // Now we need to get the second identity to also sign it + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_2.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key2, + 2, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + + // Now we need to get the second identity to sign it again to cause the error + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_2.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key2, + 3, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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::StateError( + StateError::GroupActionAlreadySignedByIdentityError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owner_requires_group_other_member_submitting_after_completion_causes_error( + ) { + // We are using a group, and two members need to sign for the event to happen + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, signer2, key2) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_3, signer3, key3) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [ + (identity.id(), 1), + (identity_2.id(), 1), + (identity_3.id(), 1), + ] + .into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + // Now we need to get the second identity to also sign it + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_2.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key2, + 2, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(101337)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + + // Now we need to get the second identity to sign it again to cause the error + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_3.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key3, + 2, + 0, + &signer3, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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::StateError( + StateError::GroupActionAlreadyCompletedError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(101337)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_by_owner_requires_group_proposer_not_in_group() { + // We are using a group, and two members need to sign for the event to happen + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_3, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity_3.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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::StateError(StateError::IdentityNotMemberOfGroupError( + _ + )), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + } + + #[test] + fn test_token_mint_by_owner_requires_group_other_signer_not_part_of_group() { + // We are using a group, and two members need to sign for the event to happen + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, signer2, key2) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_3, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_3.id(), 1)].into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + // Now we need to get the second identity to also sign it + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_2.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key2, + 2, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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::StateError(StateError::IdentityNotMemberOfGroupError( + _ + )), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_mint_other_signer_going_first_causes_error() { + // We are using a group, and the second member gets a bit hasty and signs first + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, signer2, key2) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: + false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (identity_2.id(), 1)].into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + // The second identity to also sign it + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + let confirm_token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity_2.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some( + GroupStateTransitionInfoStatus::GroupStateTransitionInfoOtherSigner( + GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: false, + }, + ), + ), + &key2, + 2, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let confirm_token_mint_serialized_transition = confirm_token_mint_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![confirm_token_mint_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::StateError(StateError::GroupActionDoesNotExistError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + } + } + + mod token_burn_tests { + use super::*; + + #[test] + fn test_token_burn() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = BatchTransition::new_token_burn_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::SuccessfulExecution(_, _)] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000 - 1337; + assert_eq!(token_balance, Some(expected_amount)); + } + + #[test] + fn test_token_burn_trying_to_burn_more_than_we_have() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = BatchTransition::new_token_burn_transition( + token_id, + identity.id(), + contract.id(), + 0, + 200000, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::StateError( + StateError::IdentityDoesNotHaveEnoughTokenBalanceError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); // nothing was burned + } + + #[test] + fn test_token_burn_gives_error_if_trying_to_burn_from_not_allowed_identity() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (contract_owner_identity, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + contract_owner_identity.id(), + None::, + None, + platform_version, + ); + + let documents_batch_create_transition = BatchTransition::new_token_burn_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_create_serialized_transition = + documents_batch_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![documents_batch_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::StateError(StateError::UnauthorizedTokenActionError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + contract_owner_identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + } + + mod token_transfer_tests { + use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers; + use dpp::data_contract::change_control_rules::ChangeControlRules; + use dpp::data_contract::change_control_rules::v0::ChangeControlRulesV0; + use dpp::data_contract::group::Group; + use dpp::state_transition::batch_transition::TokenMintTransition; + use dpp::data_contract::group::v0::GroupV0; + use dpp::group::{GroupStateTransitionInfo, GroupStateTransitionInfoStatus}; + use dpp::identity::SecurityLevel; + use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; + use dpp::state_transition::batch_transition::batched_transition::token_transition::TokenTransition; + use dpp::state_transition::StateTransition; + use dpp::state_transition::batch_transition::batched_transition::BatchedTransitionMutRef; + use dpp::state_transition::batch_transition::token_base_transition::token_base_transition_accessors::TokenBaseTransitionAccessors; + use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; + use super::*; + + #[test] + fn test_token_transfer() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (recipient, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let token_transfer_transition = BatchTransition::new_token_transfer_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + recipient.id(), + None, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_transfer_serialized_transition = token_transfer_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![token_transfer_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000 - 1337; + assert_eq!(token_balance, Some(expected_amount)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 1337; + assert_eq!(token_balance, Some(expected_amount)); + } + + #[test] + fn test_token_transfer_to_ourself_should_fail() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let token_transfer_transition = BatchTransition::new_token_transfer_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + identity.id(), + None, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_transfer_serialized_transition = token_transfer_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![token_transfer_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::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::TokenTransferToOurselfError(_)) + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, Some(100000)); + } + + #[test] + fn test_token_transfer_trying_to_send_more_than_we_have() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (recipient, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + None::, + None, + platform_version, + ); + + let token_transfer_transition = BatchTransition::new_token_transfer_transition( + token_id, + identity.id(), + contract.id(), + 0, + 200000, + recipient.id(), + None, + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_transfer_serialized_transition = token_transfer_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![token_transfer_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::StateError( + StateError::IdentityDoesNotHaveEnoughTokenBalanceError(_) + ), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000; + assert_eq!(token_balance, Some(expected_amount)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + + #[test] + fn test_token_transfer_adding_group_info_causes_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (recipient, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + // let's start by creating a real action + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_manual_minting_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::Group(0), + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }, + )); + }), + Some( + [( + 0, + Group::V0(GroupV0 { + members: [(identity.id(), 1), (recipient.id(), 1)].into(), + required_power: 2, + }), + )] + .into(), + ), + platform_version, + ); + + let token_mint_transition = BatchTransition::new_token_mint_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + Some(identity.id()), + None, + Some(GroupStateTransitionInfoStatus::GroupStateTransitionInfoProposer(0)), + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_mint_serialized_transition = token_mint_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![token_mint_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"); + + let action_id = TokenMintTransition::calculate_action_id_with_fields( + token_id.as_bytes(), + identity.id().as_bytes(), + 2, + 1337, + ); + + let mut token_transfer_transition = BatchTransition::new_token_transfer_transition( + token_id, + identity.id(), + contract.id(), + 0, + 200000, + recipient.id(), + None, + None, + None, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + // here we add fake info + match &mut token_transfer_transition { + StateTransition::Batch(batch) => { + let first_transition = batch + .first_transition_mut() + .expect("expected_first_transition"); + match first_transition { + BatchedTransitionMutRef::Token(token) => match token { + TokenTransition::Transfer(transfer) => transfer + .base_mut() + .set_using_group_info(Some(GroupStateTransitionInfo { + group_contract_position: 0, + action_id, + action_is_proposer: true, + })), + _ => {} + }, + _ => {} + } + } + _ => {} + } + + token_transfer_transition + .sign_external(&key, &signer, Some(|_, _| Ok(SecurityLevel::HIGH))) + .expect("expected to resign transaction"); + + let token_transfer_serialized_transition = token_transfer_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![token_transfer_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::UnpaidConsensusError( + ConsensusError::BasicError( + BasicError::GroupActionNotAllowedOnTransitionError(_) + ) + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000; + assert_eq!(token_balance, Some(expected_amount)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + assert_eq!(token_balance, None); + } + } + + mod token_freeze_tests { + use super::*; + use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; + + #[test] + fn test_token_freeze() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_freeze_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::ContractOwner, + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }, + )); + }), + None, + platform_version, + ); + + let freeze_transition = BatchTransition::new_token_freeze_transition( + token_id, + identity.id(), + contract.id(), + 0, + identity_2.id(), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let freeze_serialized_transition = freeze_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![freeze_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"); + + let token_frozen = platform + .drive + .fetch_identity_token_info( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token info") + .map(|info| info.frozen()); + assert_eq!(token_frozen, Some(true)); + } + + #[test] + fn test_token_freeze_and_unfreeze() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (identity_2, _, _) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_freeze_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::ContractOwner, + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }, + )); + token_configuration.set_unfreeze_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::ContractOwner, + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }, + )); + }), + None, + platform_version, + ); + + let freeze_transition = BatchTransition::new_token_freeze_transition( + token_id, + identity.id(), + contract.id(), + 0, + identity_2.id(), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let freeze_serialized_transition = freeze_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![freeze_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"); + + let token_frozen = platform + .drive + .fetch_identity_token_info( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token info") + .map(|info| info.frozen()); + assert_eq!(token_frozen, Some(true)); + + let unfreeze_transition = BatchTransition::new_token_unfreeze_transition( + token_id, + identity.id(), + contract.id(), + 0, + identity_2.id(), + None, + None, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let unfreeze_serialized_transition = unfreeze_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![unfreeze_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"); + + let token_frozen = platform + .drive + .fetch_identity_token_info( + token_id.to_buffer(), + identity_2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token info") + .map(|info| info.frozen()); + assert_eq!(token_frozen, Some(false)); + } + + #[test] + fn test_token_frozen_receive_balance_allowed_sending_not_allowed_till_unfrozen() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state(); + + let mut rng = StdRng::seed_from_u64(49853); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (recipient, signer2, key2) = + setup_identity(&mut platform, rng.gen(), dash_to_credits!(0.5)); + + let (contract, token_id) = create_token_contract_with_owner_identity( + &mut platform, + identity.id(), + Some(|token_configuration: &mut TokenConfiguration| { + token_configuration.set_freeze_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::ContractOwner, + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }, + )); + token_configuration.set_unfreeze_rules(ChangeControlRules::V0( + ChangeControlRulesV0 { + authorized_to_make_change: AuthorizedActionTakers::ContractOwner, + authorized_to_change_authorized_action_takers: + AuthorizedActionTakers::NoOne, + changing_authorized_action_takers_to_no_one_allowed: false, + changing_authorized_action_takers_to_contract_owner_allowed: false, + }, + )); + }), + None, + platform_version, + ); + + let freeze_transition = BatchTransition::new_token_freeze_transition( + token_id, + identity.id(), + contract.id(), + 0, + recipient.id(), + None, + None, + &key, + 2, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let freeze_serialized_transition = freeze_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![freeze_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"); + + let token_frozen = platform + .drive + .fetch_identity_token_info( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token info") + .map(|info| info.frozen()); + assert_eq!(token_frozen, Some(true)); + + let token_transfer_transition = BatchTransition::new_token_transfer_transition( + token_id, + identity.id(), + contract.id(), + 0, + 1337, + recipient.id(), + None, + None, + None, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_transfer_serialized_transition = token_transfer_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![token_transfer_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000 - 1337; + assert_eq!(token_balance, Some(expected_amount)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 1337; + assert_eq!(token_balance, Some(expected_amount)); + + //now let's try sending our balance + + let token_transfer_back_transition = + BatchTransition::new_token_transfer_transition( + token_id, + recipient.id(), + contract.id(), + 0, + 300, + identity.id(), + None, + None, + None, + &key2, + 2, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_transfer_back_serialized_transition = token_transfer_back_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![token_transfer_back_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::StateError(StateError::IdentityTokenAccountFrozenError(_)), + _ + )] + ); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // We expect no change + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000 - 1337; + assert_eq!(token_balance, Some(expected_amount)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 1337; + assert_eq!(token_balance, Some(expected_amount)); + + let unfreeze_transition = BatchTransition::new_token_unfreeze_transition( + token_id, + identity.id(), + contract.id(), + 0, + recipient.id(), + None, + None, + &key, + 4, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let unfreeze_serialized_transition = unfreeze_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![unfreeze_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"); + + let token_frozen = platform + .drive + .fetch_identity_token_info( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token info") + .map(|info| info.frozen()); + assert_eq!(token_frozen, Some(false)); + + let token_transfer_transition = BatchTransition::new_token_transfer_transition( + token_id, + recipient.id(), + contract.id(), + 0, + 300, + identity.id(), + None, + None, + None, + &key2, + 3, + 0, + &signer2, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let token_transfer_serialized_transition = token_transfer_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![token_transfer_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"); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 100000 - 1337 + 300; + assert_eq!(token_balance, Some(expected_amount)); + + let token_balance = platform + .drive + .fetch_identity_token_balance( + token_id.to_buffer(), + recipient.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch token balance"); + let expected_amount = 1337 - 300; + assert_eq!(token_balance, Some(expected_amount)); + } + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/mod.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/data_triggers.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/data_triggers.rs similarity index 76% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/data_triggers.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/data_triggers.rs index 47a71a2e69..554fac6807 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/data_triggers.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/data_triggers.rs @@ -1,11 +1,11 @@ use crate::error::Error; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{ +use crate::execution::validation::state_transition::batch::data_triggers::{ data_trigger_bindings_list, DataTriggerExecutionContext, DataTriggerExecutionResult, DataTriggerExecutor, }; use dpp::version::PlatformVersion; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; #[allow(dead_code)] #[deprecated(note = "This function is marked as unused.")] @@ -18,12 +18,6 @@ pub(super) fn execute_data_triggers( let data_trigger_bindings = data_trigger_bindings_list(platform_version)?; for document_transition_action in document_transition_actions { - if matches!( - document_transition_action, - DocumentTransitionAction::BumpIdentityDataContractNonce(_) - ) { - continue; - } let data_trigger_execution_result = document_transition_action .validate_with_data_triggers(&data_trigger_bindings, context, platform_version)?; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_contender.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_contender.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_contender.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_contender.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs similarity index 97% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs index 8db9245d3f..c206b54bd5 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs @@ -14,10 +14,10 @@ use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use dpp::document::Document; use dpp::fee::fee_result::FeeResult; use dpp::platform_value::{Identifier, Value}; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::{ +use dpp::state_transition::batch_transition::batched_transition::document_transition::{ DocumentTransition, DocumentTransitionV0Methods, }; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; use dpp::validation::ConsensusValidationResult; use dpp::version::PlatformVersion; use drive::drive::document::query::query_contested_documents_storage::QueryContestedDocumentsOutcomeV0Methods; 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 new file mode 100644 index 0000000000..5b225e70a7 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/mod.rs @@ -0,0 +1,302 @@ +use dpp::block::block_info::BlockInfo; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::state_error::StateError; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::batch_transition::BatchTransition; +use dpp::state_transition::StateTransitionLike; +use drive::state_transition_action::StateTransitionAction; +use dpp::version::{DefaultForPlatformVersion, PlatformVersion}; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use drive::state_transition_action::batch::BatchTransitionAction; +use drive::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; +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::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; +use crate::execution::validation::state_transition::ValidationMode; +use crate::platform_types::platform_state::v0::PlatformStateV0Methods; + +mod data_triggers; +pub mod fetch_contender; +pub mod fetch_documents; + +pub(in crate::execution::validation::state_transition::state_transitions::batch) trait DocumentsBatchStateTransitionStateValidationV0 +{ + fn validate_state_v0( + &self, + action: BatchTransitionAction, + platform: &PlatformStateRef, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + tx: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error>; + + fn transform_into_action_v0( + &self, + platform: &PlatformStateRef, + block_info: &BlockInfo, + validation_mode: ValidationMode, + tx: TransactionArg, + ) -> Result, Error>; +} + +impl DocumentsBatchStateTransitionStateValidationV0 for BatchTransition { + fn validate_state_v0( + &self, + mut state_transition_action: BatchTransitionAction, + platform: &PlatformStateRef, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut validation_result = ConsensusValidationResult::::new(); + + let state_transition_execution_context = + StateTransitionExecutionContext::default_for_platform_version(platform_version)?; + + let owner_id = state_transition_action.owner_id(); + + let mut validated_transitions = vec![]; + + let data_trigger_bindings = if platform.config.execution.use_document_triggers { + data_trigger_bindings_list(platform_version)? + } else { + vec![] + }; + + // Next we need to validate the structure of all actions (this means with the data contract) + for transition in state_transition_action.transitions_take() { + let transition_validation_result = match &transition { + BatchedTransitionAction::DocumentAction(document_action) => match document_action { + DocumentTransitionAction::CreateAction(create_action) => create_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + DocumentTransitionAction::ReplaceAction(replace_action) => replace_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + DocumentTransitionAction::TransferAction(transfer_action) => transfer_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + DocumentTransitionAction::DeleteAction(delete_action) => delete_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + DocumentTransitionAction::UpdatePriceAction(update_price_action) => { + update_price_action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )? + } + DocumentTransitionAction::PurchaseAction(purchase_action) => purchase_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + }, + BatchedTransitionAction::TokenAction(token_action) => match token_action { + TokenTransitionAction::BurnAction(burn_action) => burn_action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::MintAction(mint_action) => mint_action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::TransferAction(transfer_action) => transfer_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::FreezeAction(freeze_action) => freeze_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::UnfreezeAction(unfreeze_action) => unfreeze_action + .validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + TokenTransitionAction::EmergencyActionAction(emergency_action_action) => { + emergency_action_action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )? + } + TokenTransitionAction::DestroyFrozenFundsAction( + destroy_frozen_funds_action, + ) => destroy_frozen_funds_action.validate_state( + platform, + owner_id, + block_info, + execution_context, + transaction, + platform_version, + )?, + }, + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { + return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "we should never start with a bump identity data contract nonce", + ))); + } + }; + + if !transition_validation_result.is_valid() { + // If a state transition isn't valid we still need to bump the identity data contract nonce + validation_result.add_errors(transition_validation_result.errors); + validated_transitions.push(BatchedTransitionAction::BumpIdentityDataContractNonce( + BumpIdentityDataContractNonceAction::try_from_batched_transition_action( + transition, + owner_id, + state_transition_action.user_fee_increase(), + )?, + )); + } else if platform.config.execution.use_document_triggers { + if let BatchedTransitionAction::DocumentAction(document_transition) = &transition { + // we should also validate document triggers + let data_trigger_execution_context = DataTriggerExecutionContext { + platform, + transaction, + owner_id: &self.owner_id(), + state_transition_execution_context: &state_transition_execution_context, + }; + let data_trigger_execution_result = document_transition + .validate_with_data_triggers( + &data_trigger_bindings, + &data_trigger_execution_context, + platform_version, + )?; + + if !data_trigger_execution_result.is_valid() { + // If a state transition isn't valid because of data triggers we still need + // to bump the identity data contract nonce + let consensus_errors: Vec = data_trigger_execution_result + .errors + .into_iter() + .map(|e| ConsensusError::StateError(StateError::DataTriggerError(e))) + .collect(); + validation_result.add_errors(consensus_errors); + validated_transitions + .push(BatchedTransitionAction::BumpIdentityDataContractNonce( + BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action( + document_transition.base(), + owner_id, + state_transition_action.user_fee_increase(), + ), + )); + } else { + validated_transitions.push(transition); + } + } else { + validated_transitions.push(transition); + } + } else { + validated_transitions.push(transition); + } + } + + state_transition_action.set_transitions(validated_transitions); + + validation_result.set_data(state_transition_action.into()); + + Ok(validation_result) + } + + fn transform_into_action_v0( + &self, + platform: &PlatformStateRef, + block_info: &BlockInfo, + validation_mode: ValidationMode, + tx: TransactionArg, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + let mut execution_context = + StateTransitionExecutionContext::default_for_platform_version(platform_version)?; + + let validation_result = self.try_into_action_v0( + platform, + block_info, + validation_mode.should_validate_batch_valid_against_state(), + tx, + &mut execution_context, + )?; + + Ok(validation_result.map(Into::into)) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/mod.rs similarity index 100% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/mod.rs diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs similarity index 60% rename from packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs rename to packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs index 68ec4de478..f9ed1d6d66 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/transformer/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/transformer/v0/mod.rs @@ -21,41 +21,53 @@ use dpp::document::property_names::PRICE; use dpp::document::{Document, DocumentV0Getters}; use dpp::fee::Credits; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; -use dpp::prelude::Revision; +use dpp::prelude::{Revision, UserFeeIncrease}; use dpp::validation::SimpleConsensusValidationResult; use dpp::{consensus::ConsensusError, prelude::Identifier, validation::ConsensusValidationResult}; - -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; -use dpp::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::batch_transition::batched_transition::BatchedTransitionRef; +use dpp::state_transition::batch_transition::BatchTransition; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; use dpp::state_transition::StateTransitionLike; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use drive::state_transition_action::document::documents_batch::DocumentsBatchTransitionAction; -use drive::state_transition_action::document::documents_batch::v0::DocumentsBatchTransitionActionV0; - -use crate::execution::validation::state_transition::documents_batch::state::v0::fetch_documents::fetch_documents_for_transitions_knowing_contract_and_document_type; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::BatchTransitionAction; +use drive::state_transition_action::batch::v0::BatchTransitionActionV0; + +use crate::execution::validation::state_transition::batch::state::v0::fetch_documents::fetch_documents_for_transitions_knowing_contract_and_document_type; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; -use dpp::state_transition::documents_batch_transition::document_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; +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::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; use drive::drive::contract::DataContractFetchInfo; use drive::drive::Drive; -use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; +use drive::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; +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_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; +use drive::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::TokenMintTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::token_unfreeze_transition_action::TokenUnfreezeTransitionAction; +use drive::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; use drive::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0}; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; -pub(in crate::execution::validation::state_transition::state_transitions::documents_batch) trait DocumentsBatchTransitionTransformerV0 +pub(in crate::execution::validation::state_transition::state_transitions::batch) trait BatchTransitionTransformerV0 { fn try_into_action_v0( &self, @@ -64,10 +76,10 @@ pub(in crate::execution::validation::state_transition::state_transitions::docume full_validation: bool, transaction: TransactionArg, execution_context: &mut StateTransitionExecutionContext, - ) -> Result, Error>; + ) -> Result, Error>; } -trait DocumentsBatchTransitionInternalTransformerV0 { +trait BatchTransitionInternalTransformerV0 { fn transform_document_transitions_within_contract_v0( platform: &PlatformStateRef, block_info: &BlockInfo, @@ -78,7 +90,7 @@ trait DocumentsBatchTransitionInternalTransformerV0 { execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, - ) -> Result>, Error>; + ) -> Result>, Error>; fn transform_document_transitions_within_document_type_v0( platform: &PlatformStateRef, block_info: &BlockInfo, @@ -90,9 +102,34 @@ trait DocumentsBatchTransitionInternalTransformerV0 { execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, - ) -> Result>, Error>; + ) -> Result>, Error>; + fn transform_token_transitions_within_contract_v0( + platform: &PlatformStateRef, + data_contract_id: &Identifier, + block_info: &BlockInfo, + validate_against_state: bool, + owner_id: Identifier, + token_transitions: &Vec<&TokenTransition>, + user_fee_increase: UserFeeIncrease, + transaction: TransactionArg, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result>, Error>; + /// Transfer token transition + fn transform_token_transition_v0( + drive: &Drive, + transaction: TransactionArg, + block_info: &BlockInfo, + validate_against_state: bool, + data_contract_fetch_info: Arc, + transition: &TokenTransition, + owner_id: Identifier, + user_fee_increase: UserFeeIncrease, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result, Error>; /// The data contract can be of multiple difference versions - fn transform_transition_v0( + fn transform_document_transition_v0( drive: &Drive, transaction: TransactionArg, full_validation: bool, @@ -103,7 +140,7 @@ trait DocumentsBatchTransitionInternalTransformerV0 { owner_id: Identifier, execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, - ) -> Result, Error>; + ) -> Result, Error>; fn find_replaced_document_v0<'a>( document_transition: &'a DocumentTransition, fetched_documents: &'a [Document], @@ -120,7 +157,7 @@ trait DocumentsBatchTransitionInternalTransformerV0 { ) -> SimpleConsensusValidationResult; } -impl DocumentsBatchTransitionTransformerV0 for DocumentsBatchTransition { +impl BatchTransitionTransformerV0 for BatchTransition { fn try_into_action_v0( &self, platform: &PlatformStateRef, @@ -128,39 +165,60 @@ impl DocumentsBatchTransitionTransformerV0 for DocumentsBatchTransition { validate_against_state: bool, transaction: TransactionArg, execution_context: &mut StateTransitionExecutionContext, - ) -> Result, Error> { + ) -> Result, Error> { let owner_id = self.owner_id(); let user_fee_increase = self.user_fee_increase(); let platform_version = platform.state.current_platform_version()?; - let mut transitions_by_contracts_and_types: BTreeMap< + let mut document_transitions_by_contracts_and_types: BTreeMap< &Identifier, BTreeMap<&String, Vec<&DocumentTransition>>, > = BTreeMap::new(); + let mut token_transitions_by_contracts: BTreeMap<&Identifier, Vec<&TokenTransition>> = + BTreeMap::new(); + // We want to validate by contract, and then for each document type within a contract - for document_transition in self.transitions().iter() { - let document_type = document_transition.base().document_type_name(); - let data_contract_id = document_transition.base().data_contract_id_ref(); + for transition in self.transitions_iter() { + match transition { + BatchedTransitionRef::Document(document_transition) => { + let document_type = document_transition.base().document_type_name(); + let data_contract_id = document_transition.base().data_contract_id_ref(); - match transitions_by_contracts_and_types.entry(data_contract_id) { - Entry::Vacant(v) => { - v.insert(BTreeMap::from([(document_type, vec![document_transition])])); + match document_transitions_by_contracts_and_types.entry(data_contract_id) { + Entry::Vacant(v) => { + v.insert(BTreeMap::from([(document_type, vec![document_transition])])); + } + Entry::Occupied(mut transitions_by_types_in_contract) => { + match transitions_by_types_in_contract + .get_mut() + .entry(document_type) + { + Entry::Vacant(v) => { + v.insert(vec![document_transition]); + } + Entry::Occupied(mut o) => o.get_mut().push(document_transition), + } + } + } } - Entry::Occupied(mut transitions_by_types_in_contract) => { - match transitions_by_types_in_contract - .get_mut() - .entry(document_type) - { + BatchedTransitionRef::Token(token_transition) => { + let data_contract_id = token_transition.base().data_contract_id_ref(); + + match token_transitions_by_contracts.entry(data_contract_id) { Entry::Vacant(v) => { - v.insert(vec![document_transition]); + v.insert(vec![token_transition]); + } + Entry::Occupied(mut transitions_by_tokens_in_contract) => { + transitions_by_tokens_in_contract + .get_mut() + .push(token_transition) } - Entry::Occupied(mut o) => o.get_mut().push(document_transition), } } } } - let validation_result = transitions_by_contracts_and_types + let validation_result_documents = document_transitions_by_contracts_and_types .iter() .map( |(data_contract_id, document_transitions_by_document_type)| { @@ -177,12 +235,37 @@ impl DocumentsBatchTransitionTransformerV0 for DocumentsBatchTransition { ) }, ) - .collect::>>, Error>>()?; - let validation_result = ConsensusValidationResult::flatten(validation_result); + .collect::>>, Error>>( + )?; + + let mut validation_result_tokens = token_transitions_by_contracts + .iter() + .map(|(data_contract_id, token_transitions)| { + Self::transform_token_transitions_within_contract_v0( + platform, + data_contract_id, + block_info, + validate_against_state, + owner_id, + token_transitions, + user_fee_increase, + transaction, + execution_context, + platform_version, + ) + }) + .collect::>>, Error>>( + )?; + + let mut validation_results = validation_result_documents; + + validation_results.append(&mut validation_result_tokens); + + let validation_result = ConsensusValidationResult::flatten(validation_results); if validation_result.has_data() { let (transitions, errors) = validation_result.into_data_and_errors()?; - let batch_transition_action = DocumentsBatchTransitionActionV0 { + let batch_transition_action = BatchTransitionActionV0 { owner_id, transitions, user_fee_increase, @@ -200,7 +283,59 @@ impl DocumentsBatchTransitionTransformerV0 for DocumentsBatchTransition { } } -impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition { +impl BatchTransitionInternalTransformerV0 for BatchTransition { + fn transform_token_transitions_within_contract_v0( + platform: &PlatformStateRef, + data_contract_id: &Identifier, + block_info: &BlockInfo, + validate_against_state: bool, + owner_id: Identifier, + token_transitions: &Vec<&TokenTransition>, + user_fee_increase: UserFeeIncrease, + transaction: TransactionArg, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let drive = platform.drive; + // Data Contract must exist + let Some(data_contract_fetch_info) = drive + .get_contract_with_fetch_info_and_fee( + data_contract_id.0 .0, + None, + false, + transaction, + platform_version, + )? + .1 + else { + return Ok(ConsensusValidationResult::new_with_error( + BasicError::DataContractNotPresentError(DataContractNotPresentError::new( + *data_contract_id, + )) + .into(), + )); + }; + + let validation_result = token_transitions + .iter() + .map(|token_transition| { + Self::transform_token_transition_v0( + platform.drive, + transaction, + block_info, + validate_against_state, + data_contract_fetch_info.clone(), + token_transition, + owner_id, + user_fee_increase, + execution_context, + platform_version, + ) + }) + .collect::>, Error>>()?; + let validation_result = ConsensusValidationResult::merge_many(validation_result); + Ok(validation_result) + } fn transform_document_transitions_within_contract_v0( platform: &PlatformStateRef, block_info: &BlockInfo, @@ -211,7 +346,7 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, - ) -> Result>, Error> { + ) -> Result>, Error> { let drive = platform.drive; // Data Contract must exist let Some(data_contract_fetch_info) = drive @@ -248,7 +383,8 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition platform_version, ) }) - .collect::>>, Error>>()?; + .collect::>>, Error>>( + )?; Ok(ConsensusValidationResult::flatten(validation_result)) } @@ -263,7 +399,7 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, - ) -> Result>, Error> { + ) -> Result>, Error> { // We use temporary execution context without dry run, // because despite the dryRun, we need to get the // data contract to proceed with following logic @@ -325,7 +461,7 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition .iter() .map(|transition| { // we validate every transition in this document type - Self::transform_transition_v0( + Self::transform_document_transition_v0( platform.drive, transaction, validate_against_state, @@ -338,7 +474,7 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition platform_version, ) }) - .collect::>, Error>>( + .collect::>, Error>>( )?; let result = ConsensusValidationResult::merge_many( @@ -355,7 +491,98 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition } /// The data contract can be of multiple difference versions - fn transform_transition_v0<'a>( + fn transform_token_transition_v0( + drive: &Drive, + transaction: TransactionArg, + block_info: &BlockInfo, + validate_against_state: bool, + data_contract_fetch_info: Arc, + transition: &TokenTransition, + owner_id: Identifier, + user_fee_increase: UserFeeIncrease, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let approximate_for_costs = !validate_against_state; + match transition { + TokenTransition::Burn(token_burn_transition) => { + let (batched_action, fee_result) = TokenBurnTransitionAction::try_from_borrowed_token_burn_transition_with_contract_lookup(drive, owner_id, token_burn_transition, 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)); + + Ok(batched_action) + } + TokenTransition::Mint(token_mint_transition) => { + let (batched_action, fee_result) = TokenMintTransitionAction::try_from_borrowed_token_mint_transition_with_contract_lookup(drive, owner_id, token_mint_transition, 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)); + + Ok(batched_action) + } + TokenTransition::Transfer(token_transfer_transition) => { + let (token_transfer_action, fee_result) = TokenTransferTransitionAction::try_from_borrowed_token_transfer_transition_with_contract_lookup(drive, owner_id, token_transfer_transition, approximate_for_costs, transaction, block_info, |_identifier| { + Ok(data_contract_fetch_info.clone()) + }, platform_version)?; + + execution_context + .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); + + let batched_action = BatchedTransitionAction::TokenAction( + TokenTransitionAction::TransferAction(token_transfer_action), + ); + Ok(batched_action.into()) + } + TokenTransition::Freeze(token_freeze_transition) => { + let (batched_action, fee_result) = TokenFreezeTransitionAction::try_from_borrowed_token_freeze_transition_with_contract_lookup(drive, owner_id, token_freeze_transition, 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)); + + Ok(batched_action) + } + TokenTransition::Unfreeze(token_unfreeze_transition) => { + let (batched_action, fee_result) = TokenUnfreezeTransitionAction::try_from_borrowed_token_unfreeze_transition_with_contract_lookup(drive, owner_id, token_unfreeze_transition, 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)); + + Ok(batched_action) + } + TokenTransition::DestroyFrozenFunds(destroy_frozen_funds) => { + let (batched_action, fee_result) = TokenDestroyFrozenFundsTransitionAction::try_from_borrowed_token_destroy_frozen_funds_transition_with_contract_lookup(drive, owner_id, destroy_frozen_funds, 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)); + + Ok(batched_action) + } + TokenTransition::EmergencyAction(emergency_action) => { + let (batched_action, fee_result) = TokenEmergencyActionTransitionAction::try_from_borrowed_token_emergency_action_transition_with_contract_lookup(drive, owner_id, emergency_action, 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)); + + Ok(batched_action) + } + } + } + + /// The data contract can be of multiple difference versions + fn transform_document_transition_v0<'a>( drive: &Drive, transaction: TransactionArg, validate_against_state: bool, @@ -366,12 +593,10 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition owner_id: Identifier, execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, - ) -> Result, Error> { + ) -> Result, Error> { match transition { DocumentTransition::Create(document_create_transition) => { - let result = ConsensusValidationResult::::new(); - - let (document_create_action, fee_result) = DocumentCreateTransitionAction::from_document_borrowed_create_transition_with_contract_lookup( + let (document_create_action, fee_result) = DocumentCreateTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup( drive, transaction, document_create_transition, block_info, |_identifier| { Ok(data_contract_fetch_info.clone()) @@ -380,14 +605,13 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition execution_context .add_operation(ValidationOperation::PrecalculatedOperation(fee_result)); - if result.is_valid() { - Ok(DocumentTransitionAction::CreateAction(document_create_action).into()) - } else { - Ok(result) - } + let batched_action = BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::CreateAction(document_create_action), + ); + Ok(batched_action.into()) } DocumentTransition::Replace(document_replace_transition) => { - let mut result = ConsensusValidationResult::::new(); + let mut result = ConsensusValidationResult::::new(); let validation_result = Self::find_replaced_document_v0(transition, replaced_documents); @@ -400,9 +624,11 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition owner_id, 0, ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action.into(), + batched_action.into(), validation_result.errors, )); } @@ -468,19 +694,25 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition )?; if result.is_valid() { - Ok(DocumentTransitionAction::ReplaceAction(document_replace_action).into()) + let batched_action = BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::ReplaceAction(document_replace_action), + ); + Ok(batched_action.into()) } else { Ok(result) } } DocumentTransition::Delete(document_delete_transition) => { - let action = DocumentDeleteTransitionAction::from_document_borrowed_create_transition_with_contract_lookup(document_delete_transition, |_identifier| { + let action = DocumentDeleteTransitionAction::try_from_document_borrowed_create_transition_with_contract_lookup(document_delete_transition, |_identifier| { Ok(data_contract_fetch_info.clone()) })?; - Ok(DocumentTransitionAction::DeleteAction(action).into()) + let batched_action = BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::DeleteAction(action), + ); + Ok(batched_action.into()) } DocumentTransition::Transfer(document_transfer_transition) => { - let mut result = ConsensusValidationResult::::new(); + let mut result = ConsensusValidationResult::::new(); let validation_result = Self::find_replaced_document_v0(transition, replaced_documents); @@ -528,13 +760,16 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition )?; if result.is_valid() { - Ok(DocumentTransitionAction::TransferAction(document_transfer_action).into()) + let batched_action = BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::TransferAction(document_transfer_action), + ); + Ok(batched_action.into()) } else { Ok(result) } } DocumentTransition::UpdatePrice(document_update_price_transition) => { - let mut result = ConsensusValidationResult::::new(); + let mut result = ConsensusValidationResult::::new(); let validation_result = Self::find_replaced_document_v0(transition, replaced_documents); @@ -582,16 +817,16 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition )?; if result.is_valid() { - Ok( - DocumentTransitionAction::UpdatePriceAction(document_update_price_action) - .into(), - ) + let batched_action = BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::UpdatePriceAction(document_update_price_action), + ); + Ok(batched_action.into()) } else { Ok(result) } } DocumentTransition::Purchase(document_purchase_transition) => { - let mut result = ConsensusValidationResult::::new(); + let mut result = ConsensusValidationResult::::new(); let validation_result = Self::find_replaced_document_v0(transition, replaced_documents); @@ -650,7 +885,10 @@ impl DocumentsBatchTransitionInternalTransformerV0 for DocumentsBatchTransition )?; if result.is_valid() { - Ok(DocumentTransitionAction::PurchaseAction(document_purchase_action).into()) + let batched_action = BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::PurchaseAction(document_purchase_action), + ); + Ok(batched_action.into()) } else { Ok(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 9bdc1119eb..6d81da251c 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 @@ -4,9 +4,11 @@ use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; use dpp::consensus::basic::data_contract::{ - InvalidDataContractIdError, InvalidDataContractVersionError, + InvalidDataContractIdError, InvalidDataContractVersionError, InvalidTokenBaseSupplyError, + NonContiguousContractTokenPositionsError, }; use dpp::consensus::basic::BasicError; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; use dpp::data_contract::INITIAL_DATA_CONTRACT_VERSION; use dpp::prelude::DataContract; use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; @@ -67,6 +69,38 @@ impl DataContractCreatedStateTransitionAdvancedStructureValidationV0 )); } + let expected_position = 0; + + for (token_contract_position, token_configuration) in self.data_contract().tokens() { + if expected_position != *token_contract_position { + let bump_action = StateTransitionAction::BumpIdentityNonceAction( + BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + vec![NonContiguousContractTokenPositionsError::new( + expected_position, + *token_contract_position, + ) + .into()], + )); + } + + if token_configuration.base_supply() > i64::MAX as u64 { + let bump_action = StateTransitionAction::BumpIdentityNonceAction( + BumpIdentityNonceAction::from_borrowed_data_contract_create_transition(self), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + vec![ + InvalidTokenBaseSupplyError::new(token_configuration.base_supply()).into(), + ], + )); + } + } + Ok(ConsensusValidationResult::default()) } } 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 c22ef31de1..a5a0983202 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 @@ -149,11 +149,16 @@ mod tests { use dpp::consensus::basic::BasicError; use dpp::consensus::ConsensusError; 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::DataContract; + use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dpp::serialization::PlatformSerializable; use dpp::state_transition::data_contract_create_transition::methods::DataContractCreateTransitionMethodsV0; use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition; use dpp::tests::json_document::json_document_to_contract_with_ids; + use dpp::tokens::calculate_token_id; use platform_version::version::PlatformVersion; #[test] @@ -347,4 +352,265 @@ mod tests { .unwrap() .expect("expected to commit transaction"); } + + #[test] + fn test_data_contract_creation_with_single_token() { + 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 identity_id = identity.id(); + + let base_supply_start_amount = 0; + + { + 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 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::SuccessfulExecution(_, _)] + ); + + 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_with_starting_balance() { + 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 = 10000; + + { + 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::SuccessfulExecution(_, _)] + ); + + 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, Some(base_supply_start_amount)); + } + + #[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); + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/state/v0/mod.rs index 27c7a5ce4e..3385fd125d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/state/v0/mod.rs @@ -161,8 +161,8 @@ mod tests { use super::*; #[test] - fn should_return_invalid_result_when_transform_into_action_failed() { - let platform_version = PlatformVersion::latest(); + fn should_return_invalid_result_when_transform_into_action_failed_v7() { + let platform_version = PlatformVersion::get(7).expect("expected version 7"); let identity_nonce = IdentityNonce::default(); let platform = TestPlatformBuilder::new() @@ -193,7 +193,103 @@ mod tests { // Make the contract invalid let DataContractInSerializationFormat::V0(ref mut contract) = - data_contract_for_serialization; + data_contract_for_serialization + else { + panic!("expected serialization version 0") + }; + + contract + .document_schemas + .insert("invalidType".to_string(), Value::Null); + + let transition: DataContractCreateTransition = DataContractCreateTransitionV0 { + data_contract: data_contract_for_serialization, + identity_nonce, + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + } + .into(); + + let mut execution_context = + StateTransitionExecutionContext::default_for_platform_version(platform_version) + .expect("failed to create execution context"); + + let state = platform.state.load_full(); + + let platform_ref = PlatformRef { + drive: &platform.drive, + state: &state, + config: &platform.config, + core_rpc: &platform.core_rpc, + }; + + let result = transition + .validate_state_v0::( + &platform_ref, + ValidationMode::Validator, + &Epoch::default(), + None, + &mut execution_context, + platform_version, + ) + .expect("failed to validate advanced structure"); + + assert_matches!( + result.errors.as_slice(), + [ConsensusError::BasicError( + BasicError::ContractError( + DataContractError::InvalidContractStructure(message) + ) + )] if message == "document schema must be an object: structure error: value is not a map" + ); + + assert_matches!( + result.data, + Some(StateTransitionAction::BumpIdentityNonceAction(action)) if action.identity_id() == identity_id && action.identity_nonce() == identity_nonce + ); + + // We have tons of operations here so not sure we want to assert all of them + assert!(!execution_context.operations_slice().is_empty()); + } + + #[test] + fn should_return_invalid_result_when_transform_into_action_failed_latest() { + let platform_version = PlatformVersion::latest(); + let identity_nonce = IdentityNonce::default(); + + let platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let data_contract = + get_data_contract_fixture(None, identity_nonce, platform_version.protocol_version) + .data_contract_owned(); + + let identity_id = data_contract.owner_id(); + + platform + .drive + .apply_contract( + &data_contract, + BlockInfo::default(), + true, + None, + None, + platform_version, + ) + .expect("failed to apply contract"); + + let mut data_contract_for_serialization = data_contract + .try_into_platform_versioned(platform_version) + .expect("failed to convert data contract"); + + // Make the contract invalid + let DataContractInSerializationFormat::V1(ref mut contract) = + data_contract_for_serialization + else { + panic!("expected serialization version 1") + }; contract .document_schemas @@ -413,8 +509,11 @@ mod tests { .expect("failed to convert data contract"); // Make the contract invalid - let DataContractInSerializationFormat::V0(ref mut contract) = - data_contract_for_serialization; + let DataContractInSerializationFormat::V1(ref mut contract) = + data_contract_for_serialization + else { + panic!("expected serialization version 1") + }; contract .document_schemas diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs index ef81c1a365..5435c8ad18 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/state/v0/mod.rs @@ -231,8 +231,11 @@ mod tests { .expect("failed to convert data contract"); // Make the contract invalid - let DataContractInSerializationFormat::V0(ref mut contract) = - data_contract_for_serialization; + let DataContractInSerializationFormat::V1(ref mut contract) = + data_contract_for_serialization + else { + panic!("expected serialization version 1") + }; contract .document_schemas @@ -553,8 +556,11 @@ mod tests { .expect("failed to convert data contract"); // Make the contract invalid - let DataContractInSerializationFormat::V0(ref mut contract) = - data_contract_for_serialization; + let DataContractInSerializationFormat::V1(ref mut contract) = + data_contract_for_serialization + else { + panic!("expected serialization version 1") + }; contract .document_schemas diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs deleted file mode 100644 index 32c28c43fa..0000000000 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/action_validation/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -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/documents_batch/advanced_structure/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs deleted file mode 100644 index 5ac5d1630d..0000000000 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/advanced_structure/v0/mod.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::error::Error; -use dpp::block::block_info::BlockInfo; -use dpp::consensus::basic::document::InvalidDocumentTransitionIdError; -use dpp::consensus::signature::{InvalidSignaturePublicKeySecurityLevelError, SignatureError}; -use dpp::dashcore::Network; -use dpp::document::Document; -use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; -use dpp::identity::PartialIdentity; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::{ - DocumentTransition, DocumentTransitionV0Methods, -}; - -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; -use dpp::state_transition::{StateTransitionIdentitySigned, StateTransitionLike}; - -use dpp::validation::ConsensusValidationResult; - -use dpp::version::PlatformVersion; - -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use drive::state_transition_action::document::documents_batch::DocumentsBatchTransitionAction; -use crate::execution::validation::state_transition::state_transitions::documents_batch::action_validation::document_replace_transition_action::DocumentReplaceTransitionActionValidation; -use crate::execution::validation::state_transition::state_transitions::documents_batch::action_validation::document_delete_transition_action::DocumentDeleteTransitionActionValidation; -use crate::execution::validation::state_transition::state_transitions::documents_batch::action_validation::document_create_transition_action::DocumentCreateTransitionActionValidation; -use dpp::state_transition::documents_batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -use drive::state_transition_action::StateTransitionAction; -use drive::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; -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::documents_batch::action_validation::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_transfer_transition_action::DocumentTransferTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; - -pub(in crate::execution::validation::state_transition::state_transitions::documents_batch) trait DocumentsBatchStateTransitionStructureValidationV0 -{ - fn validate_advanced_structure_from_state_v0( - &self, - block_info: &BlockInfo, - network: Network, - action: &DocumentsBatchTransitionAction, - identity: &PartialIdentity, - execution_context: &mut StateTransitionExecutionContext, - platform_version: &PlatformVersion, - ) -> Result, Error>; -} - -impl DocumentsBatchStateTransitionStructureValidationV0 for DocumentsBatchTransition { - fn validate_advanced_structure_from_state_v0( - &self, - block_info: &BlockInfo, - network: Network, - action: &DocumentsBatchTransitionAction, - identity: &PartialIdentity, - execution_context: &mut StateTransitionExecutionContext, - platform_version: &PlatformVersion, - ) -> Result, Error> { - let security_levels = action.contract_based_security_level_requirement()?; - - let signing_key = identity.loaded_public_keys.get(&self.signature_public_key_id()).ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution("the key must exist for advanced structure validation as we already fetched it during signature validation")))?; - - if !security_levels.contains(&signing_key.security_level()) { - // We only need to bump the first identity data contract nonce as that will make a replay - // attack not possible - - let first_transition = self.transitions().first().ok_or(Error::Execution(ExecutionError::CorruptedCodeExecution("There must be at least one state transition as this is already verified in basic validation")))?; - - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition( - first_transition.base(), - self.owner_id(), - self.user_fee_increase(), - ), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - vec![SignatureError::InvalidSignaturePublicKeySecurityLevelError( - InvalidSignaturePublicKeySecurityLevelError::new( - signing_key.security_level(), - security_levels, - ), - ) - .into()], - )); - } - - // We should validate that all newly created documents have valid ids - for transition in self.transitions() { - if let DocumentTransition::Create(create_transition) = transition { - // Validate the ID - let generated_document_id = Document::generate_document_id_v0( - create_transition.base().data_contract_id_ref(), - &self.owner_id(), - create_transition.base().document_type_name(), - &create_transition.entropy(), - ); - - // This hash will take 2 blocks (128 bytes) - execution_context.add_operation(ValidationOperation::DoubleSha256(2)); - - let id = create_transition.base().id(); - if generated_document_id != id { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition( - transition.base(), - self.owner_id(), - self.user_fee_increase(), - ), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - vec![ - InvalidDocumentTransitionIdError::new(generated_document_id, id).into(), - ], - )); - } - } - } - - // Next we need to validate the structure of all actions (this means with the data contract) - for transition in action.transitions() { - match transition { - DocumentTransitionAction::CreateAction(create_action) => { - let result = create_action.validate_structure( - identity.id, - block_info, - network, - platform_version, - )?; - if !result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the create action"), self.owner_id(), self.user_fee_increase()), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - result.errors, - )); - } - } - DocumentTransitionAction::ReplaceAction(replace_action) => { - let result = replace_action.validate_structure(platform_version)?; - if !result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the replace action"), self.owner_id(), self.user_fee_increase()), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - result.errors, - )); - } - } - DocumentTransitionAction::DeleteAction(delete_action) => { - let result = delete_action.validate_structure(platform_version)?; - if !result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the delete action"), self.owner_id(), self.user_fee_increase()), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - result.errors, - )); - } - } - DocumentTransitionAction::TransferAction(transfer_action) => { - let result = transfer_action.validate_structure(platform_version)?; - if !result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the transfer action"), self.owner_id(), self.user_fee_increase()), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - result.errors, - )); - } - } - DocumentTransitionAction::UpdatePriceAction(update_price_action) => { - let result = update_price_action.validate_structure(platform_version)?; - if !result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the update price action"), self.owner_id(), self.user_fee_increase()), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - result.errors, - )); - } - } - DocumentTransitionAction::PurchaseAction(purchase_action) => { - let result = purchase_action.validate_structure(platform_version)?; - if !result.is_valid() { - let bump_action = StateTransitionAction::BumpIdentityDataContractNonceAction( - BumpIdentityDataContractNonceAction::from_borrowed_document_base_transition_action(transition.base().expect("there is always a base for the purchase action"), self.owner_id(), self.user_fee_increase()), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - result.errors, - )); - } - } - DocumentTransitionAction::BumpIdentityDataContractNonce(_) => { - return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( - "we should not have a bump identity contract nonce at this stage", - ))); - } - } - } - Ok(ConsensusValidationResult::new()) - } -} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs deleted file mode 100644 index 5ee90a17ab..0000000000 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/mod.rs +++ /dev/null @@ -1,231 +0,0 @@ -use dpp::block::block_info::BlockInfo; -use dpp::consensus::ConsensusError; -use dpp::consensus::state::state_error::StateError; -use dpp::prelude::ConsensusValidationResult; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; -use dpp::state_transition::StateTransitionLike; -use drive::state_transition_action::StateTransitionAction; -use dpp::version::{DefaultForPlatformVersion, PlatformVersion}; -use drive::grovedb::TransactionArg; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use drive::state_transition_action::document::documents_batch::DocumentsBatchTransitionAction; -use drive::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; -use crate::error::Error; -use crate::error::execution::ExecutionError; -use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_create_transition_action::DocumentCreateTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_delete_transition_action::DocumentDeleteTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_purchase_transition_action::DocumentPurchaseTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_replace_transition_action::DocumentReplaceTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_transfer_transition_action::DocumentTransferTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::action_validation::document_update_price_transition_action::DocumentUpdatePriceTransitionActionValidation; -use crate::execution::validation::state_transition::documents_batch::data_triggers::{data_trigger_bindings_list, DataTriggerExecutionContext, DataTriggerExecutor}; -use crate::platform_types::platform::{PlatformStateRef}; -use crate::execution::validation::state_transition::state_transitions::documents_batch::transformer::v0::DocumentsBatchTransitionTransformerV0; -use crate::execution::validation::state_transition::ValidationMode; -use crate::platform_types::platform_state::v0::PlatformStateV0Methods; - -mod data_triggers; -pub mod fetch_contender; -pub mod fetch_documents; - -pub(in crate::execution::validation::state_transition::state_transitions::documents_batch) trait DocumentsBatchStateTransitionStateValidationV0 -{ - fn validate_state_v0( - &self, - action: DocumentsBatchTransitionAction, - platform: &PlatformStateRef, - block_info: &BlockInfo, - execution_context: &mut StateTransitionExecutionContext, - tx: TransactionArg, - platform_version: &PlatformVersion, - ) -> Result, Error>; - - fn transform_into_action_v0( - &self, - platform: &PlatformStateRef, - block_info: &BlockInfo, - validation_mode: ValidationMode, - tx: TransactionArg, - ) -> Result, Error>; -} - -impl DocumentsBatchStateTransitionStateValidationV0 for DocumentsBatchTransition { - fn validate_state_v0( - &self, - mut state_transition_action: DocumentsBatchTransitionAction, - platform: &PlatformStateRef, - block_info: &BlockInfo, - execution_context: &mut StateTransitionExecutionContext, - transaction: TransactionArg, - platform_version: &PlatformVersion, - ) -> Result, Error> { - let mut validation_result = ConsensusValidationResult::::new(); - - let state_transition_execution_context = - StateTransitionExecutionContext::default_for_platform_version(platform_version)?; - - let owner_id = state_transition_action.owner_id(); - - let mut validated_transitions = vec![]; - - let data_trigger_bindings = if platform.config.execution.use_document_triggers { - data_trigger_bindings_list(platform_version)? - } else { - vec![] - }; - - // Next we need to validate the structure of all actions (this means with the data contract) - for transition in state_transition_action.transitions_take() { - let transition_validation_result = match &transition { - DocumentTransitionAction::CreateAction(create_action) => create_action - .validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )?, - DocumentTransitionAction::ReplaceAction(replace_action) => replace_action - .validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )?, - DocumentTransitionAction::TransferAction(transfer_action) => transfer_action - .validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )?, - DocumentTransitionAction::DeleteAction(delete_action) => delete_action - .validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )?, - DocumentTransitionAction::UpdatePriceAction(update_price_action) => { - update_price_action.validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )? - } - DocumentTransitionAction::PurchaseAction(purchase_action) => purchase_action - .validate_state( - platform, - owner_id, - block_info, - execution_context, - transaction, - platform_version, - )?, - DocumentTransitionAction::BumpIdentityDataContractNonce(..) => { - return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( - "we should never start with a bump identity data contract nonce", - ))); - } - }; - - if !transition_validation_result.is_valid() { - // If a state transition isn't valid we still need to bump the identity data contract nonce - validation_result.add_errors(transition_validation_result.errors); - validated_transitions.push( - DocumentTransitionAction::BumpIdentityDataContractNonce( - BumpIdentityDataContractNonceAction::from_document_base_transition_action( - transition.base_owned().ok_or(Error::Execution( - ExecutionError::CorruptedCodeExecution( - "base should always exist on transition", - ), - ))?, - owner_id, - state_transition_action.user_fee_increase(), - ), - ), - ); - } else if platform.config.execution.use_document_triggers { - // we should also validate document triggers - let data_trigger_execution_context = DataTriggerExecutionContext { - platform, - transaction, - owner_id: &self.owner_id(), - state_transition_execution_context: &state_transition_execution_context, - }; - let data_trigger_execution_result = transition.validate_with_data_triggers( - &data_trigger_bindings, - &data_trigger_execution_context, - platform_version, - )?; - - if !data_trigger_execution_result.is_valid() { - // If a state transition isn't valid because of data triggers we still need - // to bump the identity data contract nonce - let consensus_errors: Vec = data_trigger_execution_result - .errors - .into_iter() - .map(|e| ConsensusError::StateError(StateError::DataTriggerError(e))) - .collect(); - validation_result.add_errors(consensus_errors); - validated_transitions - .push(DocumentTransitionAction::BumpIdentityDataContractNonce( - BumpIdentityDataContractNonceAction::from_document_base_transition_action( - transition.base_owned().ok_or(Error::Execution( - ExecutionError::CorruptedCodeExecution( - "base should always exist on transition", - ), - ))?, - owner_id, - state_transition_action.user_fee_increase(), - ), - )); - } else { - validated_transitions.push(transition); - } - } else { - validated_transitions.push(transition); - } - } - - state_transition_action.set_transitions(validated_transitions); - - validation_result.set_data(state_transition_action.into()); - - Ok(validation_result) - } - - fn transform_into_action_v0( - &self, - platform: &PlatformStateRef, - block_info: &BlockInfo, - validation_mode: ValidationMode, - tx: TransactionArg, - ) -> Result, Error> { - let platform_version = platform.state.current_platform_version()?; - - let mut execution_context = - StateTransitionExecutionContext::default_for_platform_version(platform_version)?; - - let validation_result = self.try_into_action_v0( - platform, - block_info, - validation_mode.should_validate_document_valid_against_state(), - tx, - &mut execution_context, - )?; - - Ok(validation_result.map(Into::into)) - } -} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs index 1e0d8bf4b0..4b9f552345 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs @@ -215,7 +215,121 @@ mod tests { use std::collections::BTreeMap; #[test] - fn test_identity_create_validation() { + fn test_identity_create_validation_first_protocol_version() { + let platform_version = PlatformVersion::first(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .with_initial_protocol_version(1) + .build_with_mock_rpc() + .set_initial_state_structure(); + + let platform_state = platform.state.load(); + + let mut signer = SimpleSigner::default(); + + let mut rng = StdRng::seed_from_u64(567); + + let (master_key, master_private_key) = + IdentityPublicKey::random_ecdsa_master_authentication_key( + 0, + Some(58), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(master_key.clone(), master_private_key.clone()); + + let (key, private_key) = IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(999), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(key.clone(), private_key.clone()); + + let (_, pk) = ECDSA_SECP256K1 + .random_public_and_private_key_data(&mut rng, platform_version) + .unwrap(); + + let asset_lock_proof = instant_asset_lock_proof_fixture( + Some(PrivateKey::from_slice(pk.as_slice(), Network::Testnet).unwrap()), + None, + ); + + let identifier = asset_lock_proof + .create_identifier() + .expect("expected an identifier"); + + let identity: Identity = IdentityV0 { + id: identifier, + public_keys: BTreeMap::from([(0, master_key.clone()), (1, key.clone())]), + balance: 1000000000, + revision: 0, + } + .into(); + + let identity_create_transition: StateTransition = + IdentityCreateTransition::try_from_identity_with_signer( + &identity, + asset_lock_proof, + pk.as_slice(), + &signer, + &NativeBlsModule, + 0, + platform_version, + ) + .expect("expected an identity create transition"); + + let identity_create_serialized_transition = identity_create_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 1871240); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let identity_balance = platform + .drive + .fetch_identity_balance(identity.id().into_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected there to be an identity balance for this identity"); + + assert_eq!(identity_balance, 99913915760); + } + + #[test] + fn test_identity_create_validation_latest_protocol_version() { let platform_version = PlatformVersion::latest(); let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { @@ -309,7 +423,230 @@ mod tests { assert_eq!(processing_result.valid_count(), 1); - assert_eq!(processing_result.aggregated_fees().processing_fee, 1871240); + assert_eq!(processing_result.aggregated_fees().processing_fee, 1919540); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let identity_balance = platform + .drive + .fetch_identity_balance(identity.id().into_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected there to be an identity balance for this identity"); + + assert_eq!(identity_balance, 99913867460); + } + + #[test] + fn test_identity_create_asset_lock_reuse_after_issue_first_protocol_version() { + let platform_version = PlatformVersion::first(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .with_initial_protocol_version(1) + .build_with_mock_rpc() + .set_initial_state_structure(); + + let platform_state = platform.state.load(); + + let mut signer = SimpleSigner::default(); + + let mut rng = StdRng::seed_from_u64(567); + + let (master_key, master_private_key) = + IdentityPublicKey::random_ecdsa_master_authentication_key( + 0, + Some(58), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(master_key.clone(), master_private_key.clone()); + + let (critical_public_key_that_is_already_in_system, private_key) = + IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(999), + platform_version, + ) + .expect("expected to get key pair"); + + // Let's start by adding this critical key to another identity + + let (another_master_key, _) = IdentityPublicKey::random_ecdsa_master_authentication_key( + 0, + Some(53), + platform_version, + ) + .expect("expected to get key pair"); + + let identity_already_in_system: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([ + (0, another_master_key.clone()), + (1, critical_public_key_that_is_already_in_system.clone()), + ]), + balance: 100000, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity_already_in_system, + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + signer.add_key( + critical_public_key_that_is_already_in_system.clone(), + private_key.clone(), + ); + + let (_, pk) = ECDSA_SECP256K1 + .random_public_and_private_key_data(&mut rng, platform_version) + .unwrap(); + + let asset_lock_proof = instant_asset_lock_proof_fixture( + Some(PrivateKey::from_slice(pk.as_slice(), Network::Testnet).unwrap()), + None, + ); + + let identifier = asset_lock_proof + .create_identifier() + .expect("expected an identifier"); + + let mut identity: Identity = IdentityV0 { + id: identifier, + public_keys: BTreeMap::from([ + (0, master_key.clone()), + (1, critical_public_key_that_is_already_in_system.clone()), + ]), + balance: 1000000000, + revision: 0, + } + .into(); + + let identity_create_transition: StateTransition = + IdentityCreateTransition::try_from_identity_with_signer( + &identity, + asset_lock_proof.clone(), + pk.as_slice(), + &signer, + &NativeBlsModule, + 0, + platform_version, + ) + .expect("expected an identity create transition"); + + let identity_create_serialized_transition = identity_create_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 10080700); // 10000000 penalty + 80700 processing + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // Okay now let us try to reuse the asset lock + + let (new_public_key, new_private_key) = + IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(13), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(new_public_key.clone(), new_private_key.clone()); + + // let's set the new key to the identity (replacing the one that was causing the issue + identity.set_public_keys(BTreeMap::from([ + (0, master_key.clone()), + (1, new_public_key.clone()), + ])); + + let identity_create_transition: StateTransition = + IdentityCreateTransition::try_from_identity_with_signer( + &identity, + asset_lock_proof, + pk.as_slice(), + &signer, + &NativeBlsModule, + 0, + platform_version, + ) + .expect("expected an identity create transition"); + + let identity_create_serialized_transition = identity_create_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2146900); platform .drive @@ -324,11 +661,11 @@ mod tests { .expect("expected to get identity balance") .expect("expected there to be an identity balance for this identity"); - assert_eq!(identity_balance, 99913915760); + assert_eq!(identity_balance, 99909310400); // The identity balance is smaller than if there hadn't been any issue } #[test] - fn test_identity_create_asset_lock_reuse_after_issue() { + fn test_identity_create_asset_lock_reuse_after_issue_latest_protocol_version() { let platform_version = PlatformVersion::latest(); let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { @@ -531,7 +868,7 @@ mod tests { assert_eq!(processing_result.valid_count(), 1); - assert_eq!(processing_result.aggregated_fees().processing_fee, 2146900); + assert_eq!(processing_result.aggregated_fees().processing_fee, 2195200); platform .drive @@ -546,7 +883,7 @@ mod tests { .expect("expected to get identity balance") .expect("expected there to be an identity balance for this identity"); - assert_eq!(identity_balance, 99909310400); // The identity balance is smaller than if there hadn't been any issue + assert_eq!(identity_balance, 99909262100); // The identity balance is smaller than if there hadn't been any issue } #[test] @@ -1007,8 +1344,8 @@ mod tests { } #[test] - fn test_identity_create_asset_lock_replay_attack() { - let platform_version = PlatformVersion::latest(); + fn test_identity_create_asset_lock_replay_attack_first_protocol_version() { + let platform_version = PlatformVersion::first(); let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -1019,6 +1356,7 @@ mod tests { let platform = TestPlatformBuilder::new() .with_config(platform_config) + .with_initial_protocol_version(1) .build_with_mock_rpc() .set_initial_state_structure(); @@ -1252,4 +1590,251 @@ mod tests { assert_eq!(identity_balance, 99909310400); // The identity balance is smaller than if there hadn't been any issue } + + #[test] + fn test_identity_create_asset_lock_replay_attack_latest_protocol_version() { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc() + .set_initial_state_structure(); + + let platform_state = platform.state.load(); + + let mut signer = SimpleSigner::default(); + + let mut rng = StdRng::seed_from_u64(567); + + let (master_key, master_private_key) = + IdentityPublicKey::random_ecdsa_master_authentication_key( + 0, + Some(58), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(master_key.clone(), master_private_key.clone()); + + let (critical_public_key_that_is_already_in_system, private_key) = + IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(999), + platform_version, + ) + .expect("expected to get key pair"); + + // Let's start by adding this critical key to another identity + + let (another_master_key, _) = IdentityPublicKey::random_ecdsa_master_authentication_key( + 0, + Some(53), + platform_version, + ) + .expect("expected to get key pair"); + + let identity_already_in_system: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([ + (0, another_master_key.clone()), + (1, critical_public_key_that_is_already_in_system.clone()), + ]), + balance: 100000, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity_already_in_system, + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + signer.add_key( + critical_public_key_that_is_already_in_system.clone(), + private_key.clone(), + ); + + let (_, pk) = ECDSA_SECP256K1 + .random_public_and_private_key_data(&mut rng, platform_version) + .unwrap(); + + let asset_lock_proof = instant_asset_lock_proof_fixture( + Some(PrivateKey::from_slice(pk.as_slice(), Network::Testnet).unwrap()), + None, + ); + + let identifier = asset_lock_proof + .create_identifier() + .expect("expected an identifier"); + + let mut identity: Identity = IdentityV0 { + id: identifier, + public_keys: BTreeMap::from([ + (0, master_key.clone()), + (1, critical_public_key_that_is_already_in_system.clone()), + ]), + balance: 1000000000, + revision: 0, + } + .into(); + + let identity_create_transition: StateTransition = + IdentityCreateTransition::try_from_identity_with_signer( + &identity, + asset_lock_proof.clone(), + pk.as_slice(), + &signer, + &NativeBlsModule, + 0, + platform_version, + ) + .expect("expected an identity create transition"); + + let identity_create_serialized_transition = identity_create_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.invalid_paid_count(), 1); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 10080700); // 10000000 penalty + 80700 processing + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + // let's try to replay the bad transaction + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 1); + + assert_eq!(processing_result.valid_count(), 0); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 0); + + // Okay now let us try to reuse the asset lock + + let (new_public_key, new_private_key) = + IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(13), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(new_public_key.clone(), new_private_key.clone()); + + // let's set the new key to the identity (replacing the one that was causing the issue + identity.set_public_keys(BTreeMap::from([ + (0, master_key.clone()), + (1, new_public_key.clone()), + ])); + + let identity_create_transition: StateTransition = + IdentityCreateTransition::try_from_identity_with_signer( + &identity, + asset_lock_proof, + pk.as_slice(), + &signer, + &NativeBlsModule, + 0, + platform_version, + ) + .expect("expected an identity create transition"); + + let identity_create_serialized_transition = identity_create_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_create_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.invalid_paid_count(), 0); + + assert_eq!(processing_result.invalid_unpaid_count(), 0); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2195200); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let identity_balance = platform + .drive + .fetch_identity_balance(identity.id().into_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected there to be an identity balance for this identity"); + + assert_eq!(identity_balance, 99909262100); // The identity balance is smaller than if there hadn't been any issue + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs index e3fe348207..1b35c36131 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs @@ -121,8 +121,8 @@ mod tests { use std::collections::BTreeMap; #[test] - fn test_identity_top_up_validation() { - let platform_version = PlatformVersion::latest(); + fn test_identity_top_up_validation_first_version() { + let platform_version = PlatformVersion::first(); let platform_config = PlatformConfig { testing_configs: PlatformTestConfig { disable_instant_lock_signature_verification: true, @@ -133,6 +133,7 @@ mod tests { let platform = TestPlatformBuilder::new() .with_config(platform_config) + .with_initial_protocol_version(1) .build_with_mock_rpc() .set_initial_state_structure(); @@ -249,4 +250,134 @@ mod tests { assert_eq!(identity_balance, 149993654420); // about 0.5 Dash starting balance + 1 Dash asset lock top up } + + #[test] + fn test_identity_top_up_validation_latest_version() { + let platform_version = PlatformVersion::latest(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc() + .set_initial_state_structure(); + + let platform_state = platform.state.load(); + + let mut signer = SimpleSigner::default(); + + let mut rng = StdRng::seed_from_u64(567); + + let (master_key, master_private_key) = + IdentityPublicKey::random_ecdsa_master_authentication_key( + 0, + Some(58), + platform_version, + ) + .expect("expected to get key pair"); + + signer.add_key(master_key.clone(), master_private_key.clone()); + + let (critical_public_key, private_key) = + IdentityPublicKey::random_ecdsa_critical_level_authentication_key( + 1, + Some(999), + platform_version, + ) + .expect("expected to get key pair"); + + let identity_already_in_system: Identity = IdentityV0 { + id: Identifier::random_with_rng(&mut rng), + public_keys: BTreeMap::from([ + (0, master_key.clone()), + (1, critical_public_key.clone()), + ]), + balance: 50000000000, + revision: 0, + } + .into(); + + // We just add this identity to the system first + + platform + .drive + .add_new_identity( + identity_already_in_system.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add a new identity"); + + signer.add_key(critical_public_key.clone(), private_key.clone()); + + let (_, pk) = ECDSA_SECP256K1 + .random_public_and_private_key_data(&mut rng, platform_version) + .unwrap(); + + let asset_lock_proof = instant_asset_lock_proof_fixture( + Some(PrivateKey::from_slice(pk.as_slice(), Network::Testnet).unwrap()), + None, + ); + + let identity_top_up_transition: StateTransition = + IdentityTopUpTransition::try_from_identity( + &identity_already_in_system, + asset_lock_proof, + pk.as_slice(), + 0, + platform_version, + None, + ) + .expect("expected an identity create transition"); + + let identity_top_up_serialized_transition = identity_top_up_transition + .serialize_to_bytes() + .expect("serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![identity_top_up_serialized_transition.clone()], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 588840); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit"); + + let identity_balance = platform + .drive + .fetch_identity_balance( + identity_already_in_system.id().into_buffer(), + None, + platform_version, + ) + .expect("expected to get identity balance") + .expect("expected there to be an identity balance for this identity"); + + assert_eq!(identity_balance, 149993606160); // about 0.5 Dash starting balance + 1 Dash asset lock top up + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index b0986e026d..0c7b345be7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -1,5 +1,5 @@ /// Module containing functionality related to batch processing of documents. -pub mod documents_batch; +pub mod batch; /// Module for creating an identity entity. pub mod identity_create; @@ -78,7 +78,8 @@ pub(in crate::execution) mod tests { use dpp::dashcore::{ProTxHash, Txid}; use dpp::dashcore::hashes::Hash; use dpp::data_contract::accessors::v0::DataContractV0Getters; - use dpp::data_contract::DataContract; + use dpp::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters}; + use dpp::data_contract::{DataContract, GroupContractPosition}; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::document_type::random_document::{CreateRandomDocument, DocumentFieldFillSize, DocumentFieldFillType}; use dpp::document::{Document, DocumentV0Getters, DocumentV0Setters}; @@ -90,11 +91,12 @@ pub(in crate::execution) mod tests { use dpp::identity::hash::IdentityPublicKeyHashMethodsV0; use dpp::platform_value::{Bytes32, Value}; use dpp::serialization::PlatformSerializable; - use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; - use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; + use dpp::state_transition::batch_transition::BatchTransition; + use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition; use dpp::state_transition::masternode_vote_transition::methods::MasternodeVoteTransitionMethodsV0; use dpp::state_transition::StateTransition; + use dpp::tokens::calculate_token_id; use dpp::util::hash::hash_double; use dpp::util::strings::convert_to_homograph_safe_chars; use dpp::voting::contender_structs::{Contender, ContenderV0}; @@ -123,6 +125,8 @@ pub(in crate::execution) mod tests { use crate::platform_types::epoch_info::v0::EpochInfoV0; use crate::execution::types::block_fees::v0::BlockFeesV0; use crate::execution::types::processed_block_fees_outcome::v0::ProcessedBlockFeesOutcome; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::group::Group; /// We add an identity, but we also add the same amount to system credits pub(in crate::execution) fn setup_identity_with_system_credits( @@ -478,7 +482,7 @@ pub(in crate::execution) mod tests { // Process fees let processed_block_fees = platform - .process_block_fees( + .process_block_fees_and_validate_sum_trees( &block_execution_context, block_fees_v0.into(), &transaction, @@ -894,6 +898,9 @@ pub(in crate::execution) mod tests { "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", None, None, + None::, + None, + None, ); let card_game = setup_contract( @@ -901,6 +908,9 @@ pub(in crate::execution) mod tests { "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json", None, None, + None::, + None, + None, ); let (_, _, dpns_contract) = create_dpns_name_contest_on_identities_for_contract_records( @@ -1044,7 +1054,7 @@ pub(in crate::execution) mod tests { document_2.set("preorderSalt", salt_2.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1.clone(), preorder, entropy.0, @@ -1065,7 +1075,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_2.clone(), preorder, entropy.0, @@ -1086,7 +1096,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1.clone(), domain, entropy.0, @@ -1106,7 +1116,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_2.clone(), domain, entropy.0, @@ -1245,6 +1255,9 @@ pub(in crate::execution) mod tests { "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json", None, None, + None::, + None, + None, ); let preorder = dpns_contract @@ -1354,7 +1367,7 @@ pub(in crate::execution) mod tests { document_2.set("preorderSalt", salt_2.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1.clone(), preorder, entropy.0, @@ -1375,7 +1388,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_preorder_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_2.clone(), preorder, entropy.0, @@ -1396,7 +1409,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1.clone(), domain, entropy.0, @@ -1416,7 +1429,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_2 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_2.clone(), domain, entropy.0, @@ -1576,7 +1589,7 @@ pub(in crate::execution) mod tests { document_1.set("preorderSalt", salt_1.into()); let documents_batch_create_preorder_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( preorder_document_1, preorder, entropy.0, @@ -1597,7 +1610,7 @@ pub(in crate::execution) mod tests { .expect("expected documents batch serialized state transition"); let documents_batch_create_transition_1 = - DocumentsBatchTransition::new_document_creation_transition_from_document( + BatchTransition::new_document_creation_transition_from_document( document_1, domain, entropy.0, @@ -2274,4 +2287,38 @@ pub(in crate::execution) mod tests { finished_vote_info, ) } + + pub(in crate::execution) fn create_token_contract_with_owner_identity( + platform: &mut TempPlatform, + identity_id: Identifier, + token_configuration_modification: Option, + add_groups: Option>, + platform_version: &PlatformVersion, + ) -> (DataContract, Identifier) { + let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1); + + let basic_token_contract = setup_contract( + &platform.drive, + "tests/supporting_files/contract/basic-token/basic-token.json", + Some(data_contract_id.to_buffer()), + Some(identity_id.to_buffer()), + Some(|data_contract: &mut DataContract| { + if let Some(token_configuration_modification) = token_configuration_modification { + let token_configuration = data_contract + .token_configuration_mut(0) + .expect("expected token configuration"); + token_configuration_modification(token_configuration); + } + if let Some(add_groups) = add_groups { + data_contract.set_groups(add_groups); + } + }), + None, + Some(platform_version), + ); + + let token_id = calculate_token_id(data_contract_id.as_bytes(), 0); + + (basic_token_contract, token_id.into()) + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index e078e0c8b6..cb26dd4fbc 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -98,7 +98,7 @@ impl StateTransitionActionTransformerV0 for StateTransition { execution_context, tx, ), - StateTransition::DocumentsBatch(st) => st.transform_into_action( + StateTransition::Batch(st) => st.transform_into_action( platform, block_info, validation_mode, diff --git a/packages/rs-drive-abci/src/main.rs b/packages/rs-drive-abci/src/main.rs index a8ae1adccd..67a68a4091 100644 --- a/packages/rs-drive-abci/src/main.rs +++ b/packages/rs-drive-abci/src/main.rs @@ -468,10 +468,10 @@ mod test { let path = tempdir.join("db"); fs::create_dir(&path).expect("create db dir"); - let (drive, _) = Drive::open(&path, None).expect("open drive"); - let platform_version = PlatformVersion::latest(); + let (drive, _) = Drive::open(&path, None, Some(platform_version)).expect("open drive"); + drive .create_initial_state_structure(None, platform_version) .expect("should create root tree successfully"); diff --git a/packages/rs-drive-abci/src/platform_types/platform/mod.rs b/packages/rs-drive-abci/src/platform_types/platform/mod.rs index d5d99f71b3..379c3a4b57 100644 --- a/packages/rs-drive-abci/src/platform_types/platform/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform/mod.rs @@ -180,12 +180,18 @@ impl Platform { { let config = config.unwrap_or(PlatformConfig::default_testnet()); - let (drive, current_protocol_version) = - Drive::open(path, Some(config.drive.clone())).map_err(Error::Drive)?; - - if let Some(protocol_version) = current_protocol_version { - let platform_version = PlatformVersion::get(protocol_version)?; + let default_initial_platform_version = initial_protocol_version + .map(|protocol_version| PlatformVersion::get(protocol_version)) + .transpose()?; + + let (drive, current_platform_version) = Drive::open( + path, + Some(config.drive.clone()), + default_initial_platform_version, + ) + .map_err(Error::Drive)?; + if let Some(platform_version) = current_platform_version { let Some(execution_state) = Platform::::fetch_platform_state(&drive, None, platform_version)? else { diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs index de69aff56d..1682b24321 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs @@ -5,11 +5,10 @@ use crate::platform_types::signature_verification_quorum_set::{ Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, VerificationQuorum, }; +use bincode::{Decode, Encode}; use dashcore_rpc::dashcore::hashes::Hash; use dashcore_rpc::dashcore::QuorumHash; use dashcore_rpc::json::QuorumType; -use dpp::identity::state_transition::asset_lock_proof::Encode; -use dpp::platform_serialization::de::Decode; use dpp::platform_value::Bytes32; #[derive(Debug, Clone, Encode, Decode)] diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs index bfb596e451..b06d75eacc 100644 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving_v1.rs @@ -5,11 +5,10 @@ use crate::platform_types::signature_verification_quorum_set::{ Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, ThresholdBlsPublicKey, VerificationQuorum, }; +use bincode::{Decode, Encode}; use dashcore_rpc::dashcore::hashes::Hash; use dashcore_rpc::dashcore::QuorumHash; use dpp::bls_signatures::Bls12381G2Impl; -use dpp::identity::state_transition::asset_lock_proof::Encode; -use dpp::platform_serialization::de::Decode; use dpp::platform_value::Bytes32; #[derive(Debug, Clone, Encode, Decode)] diff --git a/packages/rs-drive-abci/src/query/group_queries/group_info/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_info/mod.rs new file mode 100644 index 0000000000..00dcdac6c4 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/group_info/mod.rs @@ -0,0 +1,53 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_group_info_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_group_info_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetGroupInfoRequest, GetGroupInfoResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of group info + pub fn query_group_info( + &self, + GetGroupInfoRequest { version }: GetGroupInfoRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError("could not decode group info query".to_string()), + )); + }; + + let feature_version_bounds = &platform_version.drive_abci.query.group_queries.group_info; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "group_info".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = + self.query_group_info_v0(request_v0, platform_state, platform_version)?; + Ok(result.map(|response_v0| GetGroupInfoResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs new file mode 100644 index 0000000000..a5175ac3cf --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/group_info/v0/mod.rs @@ -0,0 +1,95 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_group_info_request::GetGroupInfoRequestV0; +use dapi_grpc::platform::v0::get_group_info_response::get_group_info_response_v0::{ + GroupInfo, GroupInfoEntry, GroupMemberEntry, +}; +use dapi_grpc::platform::v0::get_group_info_response::{ + get_group_info_response_v0, GetGroupInfoResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::data_contract::group::accessors::v0::GroupV0Getters; +use dpp::identifier::Identifier; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::error::query::QuerySyntaxError; + +impl Platform { + pub(super) fn query_group_info_v0( + &self, + GetGroupInfoRequestV0 { + contract_id, + group_contract_position, + prove, + }: GetGroupInfoRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let contract_id: Identifier = + check_validation_result_with_data!(contract_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + if group_contract_position > u16::MAX as u32 { + return Ok(QueryValidationResult::new_with_error(QueryError::Query( + QuerySyntaxError::InvalidParameter(format!( + "group contract position {} can not be over u16::MAX", + group_contract_position + )), + ))); + } + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.prove_group_info( + contract_id, + group_contract_position as u16, + None, + platform_version, + )); + + GetGroupInfoResponseV0 { + result: Some(get_group_info_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let group_info = self + .drive + .fetch_group_info( + contract_id, + group_contract_position as u16, + None, + platform_version, + )? + .map(|group| { + let members = group + .members() + .into_iter() + .map(|(member_id, power)| GroupMemberEntry { + member_id: member_id.to_vec(), + power: *power, + }) + .collect(); + GroupInfoEntry { + members, + group_required_power: group.required_power(), + } + }); + + GetGroupInfoResponseV0 { + result: Some(get_group_info_response_v0::Result::GroupInfo(GroupInfo { + group_info, + })), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/group_infos/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_infos/mod.rs new file mode 100644 index 0000000000..c21304bb75 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/group_infos/mod.rs @@ -0,0 +1,53 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_group_infos_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_group_infos_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetGroupInfosRequest, GetGroupInfosResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of group infos + pub fn query_group_infos( + &self, + GetGroupInfosRequest { version }: GetGroupInfosRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError("could not decode group infos query".to_string()), + )); + }; + + let feature_version_bounds = &platform_version.drive_abci.query.group_queries.group_infos; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "group_infos".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = + self.query_group_infos_v0(request_v0, platform_state, platform_version)?; + Ok(result.map(|response_v0| GetGroupInfosResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs b/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs new file mode 100644 index 0000000000..88787fef92 --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/group_infos/v0/mod.rs @@ -0,0 +1,127 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_group_infos_request::GetGroupInfosRequestV0; +use dapi_grpc::platform::v0::get_group_infos_response::get_group_infos_response_v0::{ + GroupInfos, GroupMemberEntry, GroupPositionInfoEntry, +}; +use dapi_grpc::platform::v0::get_group_infos_response::{ + get_group_infos_response_v0, GetGroupInfosResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::data_contract::group::accessors::v0::GroupV0Getters; +use dpp::identifier::Identifier; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::error::query::QuerySyntaxError; + +impl Platform { + pub(super) fn query_group_infos_v0( + &self, + GetGroupInfosRequestV0 { + contract_id, + start_at_group_contract_position, + count, + prove, + }: GetGroupInfosRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let config = &self.config.drive; + let contract_id: Identifier = + check_validation_result_with_data!(contract_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let limit = count + .map_or(Some(config.default_query_limit), |limit_value| { + if limit_value == 0 + || limit_value > u16::MAX as u32 + || limit_value as u16 > config.default_query_limit + { + None + } else { + Some(limit_value as u16) + } + }) + .ok_or(drive::error::Error::Query(QuerySyntaxError::InvalidLimit( + format!("limit greater than max limit {}", config.max_query_limit), + )))?; + + let start_at_group_contract_position = match start_at_group_contract_position { + None => None, + Some(start_at_group_contract_position) => { + if start_at_group_contract_position.start_group_contract_position > u16::MAX as u32 + { + return Ok(QueryValidationResult::new_with_error(QueryError::Query( + QuerySyntaxError::InvalidParameter(format!( + "start group contract position {} can not be over u16::MAX", + start_at_group_contract_position.start_group_contract_position + )), + ))); + } + Some(( + start_at_group_contract_position.start_group_contract_position as u16, + start_at_group_contract_position.start_group_contract_position_included, + )) + } + }; + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.prove_group_infos( + contract_id, + start_at_group_contract_position, + Some(limit), + None, + platform_version, + )); + + GetGroupInfosResponseV0 { + result: Some(get_group_infos_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let group_infos = self + .drive + .fetch_group_infos( + contract_id, + start_at_group_contract_position, + Some(limit), + None, + platform_version, + )? + .into_iter() + .map(|(group_contract_position, group)| { + let members = group + .members() + .into_iter() + .map(|(member_id, power)| GroupMemberEntry { + member_id: member_id.to_vec(), + power: *power, + }) + .collect(); + GroupPositionInfoEntry { + group_contract_position: group_contract_position as u32, + members, + group_required_power: group.required_power(), + } + }) + .collect(); + + GetGroupInfosResponseV0 { + result: Some(get_group_infos_response_v0::Result::GroupInfos( + GroupInfos { group_infos }, + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/group_queries/mod.rs b/packages/rs-drive-abci/src/query/group_queries/mod.rs new file mode 100644 index 0000000000..b9ae74339a --- /dev/null +++ b/packages/rs-drive-abci/src/query/group_queries/mod.rs @@ -0,0 +1,2 @@ +mod group_info; +mod group_infos; diff --git a/packages/rs-drive-abci/src/query/mod.rs b/packages/rs-drive-abci/src/query/mod.rs index 6be97cc1cf..0e161b1ae1 100644 --- a/packages/rs-drive-abci/src/query/mod.rs +++ b/packages/rs-drive-abci/src/query/mod.rs @@ -1,11 +1,13 @@ mod data_contract_based_queries; mod document_query; +mod group_queries; mod identity_based_queries; mod prefunded_specialized_balances; mod proofs; mod response_metadata; mod service; mod system; +mod token_queries; mod validator_queries; mod voting; diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 54e51348c0..9ce866c7cf 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -10,7 +10,8 @@ use crate::utils::spawn_blocking_task_with_name_if_supported; use async_trait::async_trait; use dapi_grpc::platform::v0::platform_server::Platform as PlatformService; use dapi_grpc::platform::v0::{ - BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, GetConsensusParamsRequest, + BroadcastStateTransitionRequest, BroadcastStateTransitionResponse, + GetActiveGroupActionsRequest, GetActiveGroupActionsResponse, GetConsensusParamsRequest, GetConsensusParamsResponse, GetContestedResourceIdentityVotesRequest, GetContestedResourceIdentityVotesResponse, GetContestedResourceVoteStateRequest, GetContestedResourceVoteStateResponse, GetContestedResourceVotersForIdentityRequest, @@ -20,18 +21,22 @@ use dapi_grpc::platform::v0::{ GetDataContractResponse, GetDataContractsRequest, GetDataContractsResponse, GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, - GetEvonodesProposedEpochBlocksResponse, GetIdentitiesBalancesRequest, - GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, - GetIdentitiesContractKeysResponse, GetIdentityBalanceAndRevisionRequest, + GetEvonodesProposedEpochBlocksResponse, GetGroupInfoRequest, GetGroupInfoResponse, + GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, + GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, + GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, + GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, GetIdentityBalanceAndRevisionResponse, GetIdentityBalanceRequest, GetIdentityBalanceResponse, GetIdentityByPublicKeyHashRequest, GetIdentityByPublicKeyHashResponse, GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest, GetIdentityKeysResponse, GetIdentityNonceRequest, GetIdentityNonceResponse, GetIdentityRequest, - GetIdentityResponse, GetPathElementsRequest, GetPathElementsResponse, - GetPrefundedSpecializedBalanceRequest, GetPrefundedSpecializedBalanceResponse, - GetProofsRequest, GetProofsResponse, GetProtocolVersionUpgradeStateRequest, - GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, - GetProtocolVersionUpgradeVoteStatusResponse, GetStatusRequest, GetStatusResponse, + GetIdentityResponse, GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse, + GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetPathElementsRequest, + GetPathElementsResponse, GetPrefundedSpecializedBalanceRequest, + GetPrefundedSpecializedBalanceResponse, GetProofsRequest, GetProofsResponse, + GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, + GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, + GetStatusRequest, GetStatusResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, GetTotalCreditsInPlatformRequest, GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, @@ -609,6 +614,90 @@ impl PlatformService for QueryService { ) .await } + + async fn get_identity_token_balances( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_identity_token_balances, + "query_identity_token_balances", + ) + .await + } + + async fn get_identities_token_balances( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_identities_token_balances, + "query_identities_token_balances", + ) + .await + } + + async fn get_identity_token_infos( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_identity_token_infos, + "query_identity_token_infos", + ) + .await + } + + async fn get_identities_token_infos( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_identities_token_infos, + "query_identities_token_infos", + ) + .await + } + + async fn get_token_statuses( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_token_statuses, + "get_token_statuses", + ) + .await + } + + async fn get_group_info( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_group_info, + "get_group_info", + ) + .await + } + + // async fn get_active_group_actions( + // &self, + // request: Request, + // ) -> Result, Status> { + // self.handle_blocking_query( + // request, + // Platform::::query_active_group_actions, + // "get_active_group_actions", + // ) + // .await + // } } fn query_error_into_status(error: QueryError) -> Status { diff --git a/packages/rs-drive-abci/src/query/token_queries/identities_token_balances/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identities_token_balances/mod.rs new file mode 100644 index 0000000000..f600317ce6 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identities_token_balances/mod.rs @@ -0,0 +1,66 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identities_token_balances_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_identities_token_balances_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{ + GetIdentitiesTokenBalancesRequest, GetIdentitiesTokenBalancesResponse, +}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of an identity's token balances by a public key hash + pub fn query_identities_token_balances( + &self, + GetIdentitiesTokenBalancesRequest { version }: GetIdentitiesTokenBalancesRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode identity token balances query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .token_queries + .identities_token_balances; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "identities_token_balances".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_identities_token_balances_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok( + result.map(|response_v0| GetIdentitiesTokenBalancesResponse { + version: Some(ResponseVersion::V0(response_v0)), + }), + ) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identities_token_balances/v0/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identities_token_balances/v0/mod.rs new file mode 100644 index 0000000000..b655fdd99f --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identities_token_balances/v0/mod.rs @@ -0,0 +1,88 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identities_token_balances_request::GetIdentitiesTokenBalancesRequestV0; +use dapi_grpc::platform::v0::get_identities_token_balances_response::{get_identities_token_balances_response_v0, GetIdentitiesTokenBalancesResponseV0}; +use dapi_grpc::platform::v0::get_identities_token_balances_response::get_identities_token_balances_response_v0::{IdentityTokenBalanceEntry, IdentityTokenBalances}; +use dpp::check_validation_result_with_data; +use dpp::identifier::Identifier; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_identities_token_balances_v0( + &self, + GetIdentitiesTokenBalancesRequestV0 { + token_id, + identity_ids, + prove, + }: GetIdentitiesTokenBalancesRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let token_id: Identifier = + check_validation_result_with_data!(token_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let identity_ids: Vec<[u8; 32]> = check_validation_result_with_data!(identity_ids + .into_iter() + .map(|identity_id| { + identity_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "identity_id must be a valid identifier (32 bytes long)".to_string(), + ) + }) + }) + .collect::, QueryError>>()); + + let response = if prove { + let proof = + check_validation_result_with_data!(self.drive.prove_identities_token_balances( + token_id.into_buffer(), + identity_ids.as_slice(), + None, + platform_version, + )); + + GetIdentitiesTokenBalancesResponseV0 { + result: Some(get_identities_token_balances_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let identity_token_balances = self + .drive + .fetch_identities_token_balances( + token_id.into_buffer(), + identity_ids.as_slice(), + None, + platform_version, + )? + .into_iter() + .map(|(identity_id, amount)| IdentityTokenBalanceEntry { + identity_id: identity_id.to_vec(), + balance: amount, + }) + .collect(); + + GetIdentitiesTokenBalancesResponseV0 { + result: Some( + get_identities_token_balances_response_v0::Result::IdentityTokenBalances( + IdentityTokenBalances { + identity_token_balances, + }, + ), + ), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identities_token_infos/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identities_token_infos/mod.rs new file mode 100644 index 0000000000..a1746ff1a0 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identities_token_infos/mod.rs @@ -0,0 +1,62 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identities_token_infos_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_identities_token_infos_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetIdentitiesTokenInfosRequest, GetIdentitiesTokenInfosResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of an identity's token infos by a public key hash + pub fn query_identities_token_infos( + &self, + GetIdentitiesTokenInfosRequest { version }: GetIdentitiesTokenInfosRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode identity token infos query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .token_queries + .identities_token_infos; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "identities_token_infos".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_identities_token_infos_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetIdentitiesTokenInfosResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identities_token_infos/v0/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identities_token_infos/v0/mod.rs new file mode 100644 index 0000000000..e6a0786e78 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identities_token_infos/v0/mod.rs @@ -0,0 +1,94 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identities_token_infos_request::GetIdentitiesTokenInfosRequestV0; +use dapi_grpc::platform::v0::get_identities_token_infos_response::{get_identities_token_infos_response_v0, GetIdentitiesTokenInfosResponseV0}; +use dapi_grpc::platform::v0::get_identities_token_infos_response::get_identities_token_infos_response_v0::{IdentityTokenInfos, TokenIdentityInfoEntry, TokenInfoEntry}; +use dpp::check_validation_result_with_data; +use dpp::identifier::Identifier; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_identities_token_infos_v0( + &self, + GetIdentitiesTokenInfosRequestV0 { + token_id, + identity_ids, + prove, + }: GetIdentitiesTokenInfosRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let token_id: Identifier = + check_validation_result_with_data!(token_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let identity_ids: Vec<[u8; 32]> = check_validation_result_with_data!(identity_ids + .into_iter() + .map(|identity_id| { + identity_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "identity_id must be a valid identifier (32 bytes long)".to_string(), + ) + }) + }) + .collect::, QueryError>>()); + + let response = if prove { + let proof = + check_validation_result_with_data!(self.drive.prove_identities_token_infos( + token_id.into_buffer(), + identity_ids.as_slice(), + None, + platform_version, + )); + + GetIdentitiesTokenInfosResponseV0 { + result: Some(get_identities_token_infos_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let identity_token_infos = self + .drive + .fetch_identities_token_infos( + token_id.into_buffer(), + identity_ids.as_slice(), + None, + platform_version, + )? + .into_iter() + .map(|(identity_id, info)| { + let info = info.map(|identity_token_info| TokenIdentityInfoEntry { + frozen: identity_token_info.frozen(), + }); + TokenInfoEntry { + identity_id: identity_id.to_vec(), + info, + } + }) + .collect(); + + GetIdentitiesTokenInfosResponseV0 { + result: Some( + get_identities_token_infos_response_v0::Result::IdentityTokenInfos( + IdentityTokenInfos { + token_infos: identity_token_infos, + }, + ), + ), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identity_token_balances/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identity_token_balances/mod.rs new file mode 100644 index 0000000000..acc357d809 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identity_token_balances/mod.rs @@ -0,0 +1,62 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identity_token_balances_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_identity_token_balances_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of an identity's token balances by a public key hash + pub fn query_identity_token_balances( + &self, + GetIdentityTokenBalancesRequest { version }: GetIdentityTokenBalancesRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode identity token balances query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .token_queries + .identity_token_balances; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "identity_token_balances".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_identity_token_balances_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetIdentityTokenBalancesResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identity_token_balances/v0/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identity_token_balances/v0/mod.rs new file mode 100644 index 0000000000..45a54c731c --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identity_token_balances/v0/mod.rs @@ -0,0 +1,86 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identity_token_balances_request::GetIdentityTokenBalancesRequestV0; +use dapi_grpc::platform::v0::get_identity_token_balances_response::{get_identity_token_balances_response_v0, GetIdentityTokenBalancesResponseV0}; +use dapi_grpc::platform::v0::get_identity_token_balances_response::get_identity_token_balances_response_v0::{TokenBalanceEntry, TokenBalances}; +use dpp::check_validation_result_with_data; +use dpp::identifier::Identifier; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_identity_token_balances_v0( + &self, + GetIdentityTokenBalancesRequestV0 { + identity_id, + token_ids, + prove, + }: GetIdentityTokenBalancesRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let identity_id: Identifier = + check_validation_result_with_data!(identity_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "identity_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let token_ids: Vec<[u8; 32]> = check_validation_result_with_data!(token_ids + .into_iter() + .map(|token_id| { + token_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + }) + }) + .collect::, QueryError>>()); + + let response = if prove { + let proof = + check_validation_result_with_data!(self.drive.prove_identity_token_balances( + token_ids.as_slice(), + identity_id.into_buffer(), + None, + platform_version, + )); + + GetIdentityTokenBalancesResponseV0 { + result: Some(get_identity_token_balances_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let token_balances = self + .drive + .fetch_identity_token_balances( + token_ids.as_slice(), + identity_id.into_buffer(), + None, + platform_version, + )? + .into_iter() + .map(|(token_id, amount)| TokenBalanceEntry { + token_id: token_id.to_vec(), + balance: amount, + }) + .collect(); + + GetIdentityTokenBalancesResponseV0 { + result: Some( + get_identity_token_balances_response_v0::Result::TokenBalances(TokenBalances { + token_balances, + }), + ), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identity_token_infos/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identity_token_infos/mod.rs new file mode 100644 index 0000000000..c0abc1a21e --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identity_token_infos/mod.rs @@ -0,0 +1,62 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identity_token_infos_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_identity_token_infos_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of an identity's token infos by a public key hash + pub fn query_identity_token_infos( + &self, + GetIdentityTokenInfosRequest { version }: GetIdentityTokenInfosRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode identity token infos query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .token_queries + .identity_token_infos; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "identity_token_infos".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_identity_token_infos_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetIdentityTokenInfosResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/identity_token_infos/v0/mod.rs b/packages/rs-drive-abci/src/query/token_queries/identity_token_infos/v0/mod.rs new file mode 100644 index 0000000000..c013f8e9d9 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/identity_token_infos/v0/mod.rs @@ -0,0 +1,89 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_identity_token_infos_request::GetIdentityTokenInfosRequestV0; +use dapi_grpc::platform::v0::get_identity_token_infos_response::{get_identity_token_infos_response_v0, GetIdentityTokenInfosResponseV0}; +use dapi_grpc::platform::v0::get_identity_token_infos_response::get_identity_token_infos_response_v0::{TokenIdentityInfoEntry, TokenInfoEntry, TokenInfos}; +use dpp::check_validation_result_with_data; +use dpp::identifier::Identifier; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_identity_token_infos_v0( + &self, + GetIdentityTokenInfosRequestV0 { + identity_id, + token_ids, + prove, + }: GetIdentityTokenInfosRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let identity_id: Identifier = + check_validation_result_with_data!(identity_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "identity_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let token_ids: Vec<[u8; 32]> = check_validation_result_with_data!(token_ids + .into_iter() + .map(|token_id| { + token_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + }) + }) + .collect::, QueryError>>()); + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.prove_identity_token_infos( + token_ids.as_slice(), + identity_id.into_buffer(), + None, + platform_version, + )); + + GetIdentityTokenInfosResponseV0 { + result: Some(get_identity_token_infos_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let token_infos = self + .drive + .fetch_identity_token_infos( + token_ids.as_slice(), + identity_id.into_buffer(), + None, + platform_version, + )? + .into_iter() + .map(|(token_id, info)| { + let info = info.map(|identity_token_info| TokenIdentityInfoEntry { + frozen: identity_token_info.frozen(), + }); + TokenInfoEntry { + token_id: token_id.to_vec(), + info, + } + }) + .collect(); + + GetIdentityTokenInfosResponseV0 { + result: Some(get_identity_token_infos_response_v0::Result::TokenInfos( + TokenInfos { token_infos }, + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/mod.rs b/packages/rs-drive-abci/src/query/token_queries/mod.rs new file mode 100644 index 0000000000..70f261b383 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/mod.rs @@ -0,0 +1,5 @@ +mod identities_token_balances; +mod identities_token_infos; +mod identity_token_balances; +mod identity_token_infos; +mod token_status; diff --git a/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs b/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs new file mode 100644 index 0000000000..555fce502d --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs @@ -0,0 +1,59 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_token_statuses_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_token_statuses_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetTokenStatusesRequest, GetTokenStatusesResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of token statuses + pub fn query_token_statuses( + &self, + GetTokenStatusesRequest { version }: GetTokenStatusesRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode identity token infos query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .token_queries + .token_statuses; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "token_statuses".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = + self.query_token_statuses_v0(request_v0, platform_state, platform_version)?; + Ok(result.map(|response_v0| GetTokenStatusesResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/token_status/v0/mod.rs b/packages/rs-drive-abci/src/query/token_queries/token_status/v0/mod.rs new file mode 100644 index 0000000000..8f801b8d57 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/token_status/v0/mod.rs @@ -0,0 +1,73 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_token_statuses_request::GetTokenStatusesRequestV0; +use dapi_grpc::platform::v0::get_token_statuses_response::get_token_statuses_response_v0::{ + TokenStatusEntry, TokenStatuses, +}; +use dapi_grpc::platform::v0::get_token_statuses_response::{ + get_token_statuses_response_v0, GetTokenStatusesResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::tokens::status::v0::TokenStatusV0Accessors; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_token_statuses_v0( + &self, + GetTokenStatusesRequestV0 { token_ids, prove }: GetTokenStatusesRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let token_ids: Vec<[u8; 32]> = check_validation_result_with_data!(token_ids + .into_iter() + .map(|token_id| { + token_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + }) + }) + .collect::, QueryError>>()); + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.prove_token_statuses( + token_ids.as_slice(), + None, + platform_version, + )); + + GetTokenStatusesResponseV0 { + result: Some(get_token_statuses_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let token_statuses = self + .drive + .fetch_token_statuses(token_ids.as_slice(), None, platform_version)? + .into_iter() + .map(|(token_id, status)| { + let paused = status.map(|token_status| token_status.paused()); + TokenStatusEntry { + token_id: token_id.to_vec(), + paused, + } + }) + .collect(); + + GetTokenStatusesResponseV0 { + result: Some(get_token_statuses_response_v0::Result::TokenStatuses( + TokenStatuses { token_statuses }, + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 4194e30689..9622e72459 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -27,6 +27,7 @@ mod masternodes; mod patch_platform_tests; mod query; mod strategy; +mod token_tests; mod upgrade_fork_tests; mod verify_state_transitions; mod voting_tests; @@ -462,8 +463,8 @@ mod tests { } #[test] - fn run_chain_one_identity_in_solitude() { - let platform_version = PlatformVersion::latest(); + fn run_chain_one_identity_in_solitude_first_protocol_version() { + let platform_version = PlatformVersion::first(); let strategy = NetworkStrategy { strategy: Strategy { start_contracts: vec![], @@ -508,9 +509,10 @@ mod tests { }; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(1) .build_with_mock_rpc(); - let outcome = run_chain_for_strategy(&mut platform, 100, strategy, config, 15, &mut None); + let outcome = run_chain_for_strategy(&mut platform, 2, strategy, config, 15, &mut None); let balance = outcome .abci_app @@ -527,6 +529,84 @@ mod tests { assert_eq!(balance, 99864012200) } + #[test] + fn run_chain_one_identity_in_solitude_latest_protocol_version() { + // This is different because in the root tree we added GroupActions + // 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 + + // This will cause the costs of insertion of a spent asset lock transition, since group actions now exist we will see a slight difference in processing costs + // This is because WithdrawalTransactions will have a right element in the tree. + + let platform_version = PlatformVersion::latest(); + let strategy = NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![], + start_identities: StartIdentities::default(), + identity_inserts: IdentityInsertInfo { + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + ..Default::default() + }, + + identity_contract_nonce_gaps: None, + signer: None, + }, + total_hpmns: 100, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: None, + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: true, + ..Default::default() + }; + let config = PlatformConfig { + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + verify_sum_trees: true, + + ..Default::default() + }, + block_spacing_ms: 3000, + testing_configs: PlatformTestConfig::default_minimal_verifications(), + ..Default::default() + }; + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = run_chain_for_strategy(&mut platform, 2, strategy, config, 15, &mut None); + + let balance = outcome + .abci_app + .platform + .drive + .fetch_identity_balance( + outcome.identities.first().unwrap().id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch balances") + .expect("expected to have an identity to get balance from"); + + assert_eq!(balance, 99864009940) + } + #[test] fn run_chain_core_height_randomly_increasing() { let strategy = NetworkStrategy { @@ -2270,10 +2350,7 @@ mod tests { for tx_results_per_block in outcome.state_transition_results_per_block.values() { for (state_transition, _unused_result) in tx_results_per_block { // We can't ever get a documents batch transition, because the proposer will remove it from a block - assert!(!matches!( - state_transition, - StateTransition::DocumentsBatch(_) - )); + assert!(!matches!(state_transition, StateTransition::Batch(_))); } } } @@ -2576,28 +2653,22 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index bf3235ea78..b93a8957ba 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -15,7 +15,7 @@ use strategy_tests::frequency::Frequency; use strategy_tests::operations::FinalizeBlockOperation::IdentityAddKeys; use strategy_tests::operations::{ AmountRange, DocumentAction, DocumentOp, FinalizeBlockOperation, IdentityUpdateOp, - OperationType, + OperationType, TokenOp, }; use dpp::document::DocumentV0Getters; @@ -31,57 +31,72 @@ use drive::drive::identity::key::fetch::{IdentityKeysRequest, KeyRequestType}; use drive::drive::Drive; use drive::util::storage_flags::StorageFlags::SingleEpoch; -use dpp::identity::KeyType::ECDSA_SECP256K1; -use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; -use dpp::state_transition::data_contract_update_transition::methods::DataContractUpdateTransitionMethodsV0; -use drive::query::DriveDocumentQuery; -use drive_abci::mimic::test_quorum::TestQuorumInfo; -use drive_abci::platform_types::platform::Platform; -use drive_abci::rpc::core::MockCoreRPCLike; -use rand::prelude::{IteratorRandom, SliceRandom, StdRng}; -use rand::Rng; -use strategy_tests::Strategy; -use strategy_tests::transitions::{create_state_transitions_for_identities, create_state_transitions_for_identities_and_proofs, instant_asset_lock_proof_fixture_with_dynamic_range}; -use std::borrow::Cow; -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::ops::RangeInclusive; -use std::str::FromStr; -use tenderdash_abci::proto::abci::{ExecTxResult, ValidatorSetUpdate}; +use crate::strategy::CoreHeightIncrease::NoCoreHeightIncrease; use dpp::dashcore::hashes::Hash; +use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::document_type::v0::DocumentTypeV0; use dpp::identifier::MasternodeIdentifiers; use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::identity_public_key::v0::IdentityPublicKeyV0; use dpp::identity::state_transition::asset_lock_proof::InstantAssetLockProof; +use dpp::identity::KeyType::ECDSA_SECP256K1; use dpp::platform_value::{BinaryData, Value}; use dpp::prelude::{AssetLockProof, Identifier, IdentityNonce}; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; -use dpp::state_transition::documents_batch_transition::document_create_transition::{DocumentCreateTransition, DocumentCreateTransitionV0}; -use dpp::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; -use dpp::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; -use dpp::state_transition::documents_batch_transition::{DocumentsBatchTransition, DocumentsBatchTransitionV0}; -use dpp::state_transition::documents_batch_transition::document_transition::{DocumentDeleteTransition, DocumentReplaceTransition, DocumentTransferTransition}; -use drive::drive::document::query::QueryDocumentsOutcomeV0Methods; +use dpp::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::{ + BatchedTransition, DocumentDeleteTransition, DocumentReplaceTransition, + DocumentTransferTransition, +}; +use dpp::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dpp::state_transition::batch_transition::document_create_transition::{ + DocumentCreateTransition, DocumentCreateTransitionV0, +}; +use dpp::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; +use dpp::state_transition::batch_transition::token_mint_transition::TokenMintTransitionV0; +use dpp::state_transition::batch_transition::token_transfer_transition::TokenTransferTransitionV0; +use dpp::state_transition::batch_transition::{ + BatchTransition, BatchTransitionV0, BatchTransitionV1, TokenMintTransition, + TokenTransferTransition, +}; use dpp::state_transition::data_contract_create_transition::methods::v0::DataContractCreateTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::DocumentTransferTransitionV0; -use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition; +use dpp::state_transition::data_contract_update_transition::methods::DataContractUpdateTransitionMethodsV0; use dpp::state_transition::masternode_vote_transition::methods::MasternodeVoteTransitionMethodsV0; +use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition; +use dpp::tokens::calculate_token_id; +use dpp::tokens::token_event::TokenEvent; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use dpp::voting::vote_polls::VotePoll; -use dpp::voting::votes::resource_vote::ResourceVote; use dpp::voting::votes::resource_vote::v0::ResourceVoteV0; +use dpp::voting::votes::resource_vote::ResourceVote; use dpp::voting::votes::Vote; +use drive::drive::document::query::QueryDocumentsOutcomeV0Methods; +use drive::query::DriveDocumentQuery; use drive_abci::abci::app::FullAbciApplication; -use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; use drive_abci::config::PlatformConfig; +use drive_abci::mimic::test_quorum::TestQuorumInfo; +use drive_abci::platform_types::platform::Platform; +use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; use drive_abci::platform_types::signature_verification_quorum_set::{ QuorumConfig, Quorums, SigningQuorum, }; use drive_abci::platform_types::withdrawal::unsigned_withdrawal_txs::v0::UnsignedWithdrawalTxs; - -use crate::strategy::CoreHeightIncrease::NoCoreHeightIncrease; +use drive_abci::rpc::core::MockCoreRPCLike; +use rand::prelude::{IteratorRandom, SliceRandom, StdRng}; +use rand::Rng; use simple_signer::signer::SimpleSigner; +use std::borrow::Cow; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::ops::RangeInclusive; +use std::str::FromStr; +use strategy_tests::transitions::{ + create_state_transitions_for_identities, create_state_transitions_for_identities_and_proofs, + instant_asset_lock_proof_fixture_with_dynamic_range, +}; +use strategy_tests::Strategy; +use tenderdash_abci::proto::abci::{ExecTxResult, ValidatorSetUpdate}; #[derive(Clone, Debug, Default)] pub struct MasternodeListChangesStrategy { @@ -483,6 +498,15 @@ impl NetworkStrategy { .expect("document type must exist") .to_owned_document_type(); } + } else if let OperationType::Token(token_op) = &mut operation.op_type { + if token_op.contract.id() == old_id { + token_op.contract.set_id(contract.id()); + token_op.token_id = calculate_token_id( + contract.id_ref().as_bytes(), + token_op.token_pos, + ) + .into(); + } } }); @@ -648,8 +672,8 @@ impl NetworkStrategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { + let document_batch_transition: BatchTransition = + BatchTransitionV0 { owner_id: identity.id(), transitions: vec![document_create_transition.into()], user_fee_increase: 0, @@ -778,8 +802,8 @@ impl NetworkStrategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { + let document_batch_transition: BatchTransition = + BatchTransitionV0 { owner_id: identity.id(), transitions: vec![document_create_transition.into()], user_fee_increase: 0, @@ -884,15 +908,14 @@ impl NetworkStrategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id: identity.id, - transitions: vec![document_delete_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 0, - signature: BinaryData::default(), - } - .into(); + let document_batch_transition: BatchTransition = BatchTransitionV0 { + owner_id: identity.id, + transitions: vec![document_delete_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: BinaryData::default(), + } + .into(); let mut document_batch_transition: StateTransition = document_batch_transition.into(); @@ -987,15 +1010,14 @@ impl NetworkStrategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id: identity.id, - transitions: vec![document_replace_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 0, - signature: BinaryData::default(), - } - .into(); + let document_batch_transition: BatchTransition = BatchTransitionV0 { + owner_id: identity.id, + transitions: vec![document_replace_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: BinaryData::default(), + } + .into(); let mut document_batch_transition: StateTransition = document_batch_transition.into(); @@ -1098,15 +1120,14 @@ impl NetworkStrategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id: identity.id, - transitions: vec![document_transfer_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 0, - signature: BinaryData::default(), - } - .into(); + let document_batch_transition: BatchTransition = BatchTransitionV0 { + owner_id: identity.id, + transitions: vec![document_transfer_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: BinaryData::default(), + } + .into(); let mut document_batch_transition: StateTransition = document_batch_transition.into(); @@ -1404,6 +1425,166 @@ impl NetworkStrategy { operations.push(state_transition); } } + OperationType::Token(TokenOp { + contract, + token_id, + token_pos, + use_identity_with_id, + action: TokenEvent::Mint(amount, recipient, note), + }) if current_identities.len() > 1 => { + let operation_owner_id = if let Some(identity_id) = use_identity_with_id { + *identity_id + } else { + let random_index = rng.gen_range(0..current_identities.len()); + current_identities[random_index].id() + }; + + let request = IdentityKeysRequest { + identity_id: operation_owner_id.to_buffer(), + request_type: KeyRequestType::SpecificKeys(vec![1]), + limit: Some(1), + offset: None, + }; + let identity = platform + .drive + .fetch_identity_balance_with_keys(request, None, platform_version) + .expect("expected to be able to get identity") + .expect("expected to get an identity for token mint operation"); + let identity_contract_nonce = contract_nonce_counter + .entry((operation_owner_id, contract.id())) + .or_default(); + *identity_contract_nonce += 1; + let token_mint_transition: TokenMintTransition = TokenMintTransitionV0 { + base: TokenBaseTransitionV0 { + identity_contract_nonce: *identity_contract_nonce, + token_contract_position: *token_pos, + data_contract_id: contract.id(), + token_id: *token_id, + using_group_info: None, + } + .into(), + issued_to_identity_id: Some(*recipient), + amount: *amount, + public_note: note.clone(), + } + .into(); + + let batch_transition: BatchTransition = BatchTransitionV1 { + owner_id: identity.id, + transitions: vec![BatchedTransition::Token( + token_mint_transition.into(), + )], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: BinaryData::default(), + } + .into(); + + let mut batch_transition: StateTransition = batch_transition.into(); + + let identity_public_key = identity + .loaded_public_keys + .values() + .next() + .expect("expected a key"); + + batch_transition + .sign_external( + identity_public_key, + signer, + Some(|_data_contract_id, _document_type_name| { + Ok(SecurityLevel::HIGH) + }), + ) + .expect("expected to sign"); + + operations.push(batch_transition); + } + OperationType::Token(TokenOp { + contract, + token_id, + token_pos, + use_identity_with_id, + action: + TokenEvent::Transfer( + recipient, + public_note, + shared_encrypted_note, + private_encrypted_note, + amount, + ), + }) if current_identities.len() > 1 => { + let operation_owner_id = if let Some(identity_id) = use_identity_with_id { + *identity_id + } else { + let random_index = rng.gen_range(0..current_identities.len()); + current_identities[random_index].id() + }; + + let request = IdentityKeysRequest { + identity_id: operation_owner_id.to_buffer(), + request_type: KeyRequestType::SpecificKeys(vec![1]), + limit: Some(1), + offset: None, + }; + let identity = platform + .drive + .fetch_identity_balance_with_keys(request, None, platform_version) + .expect("expected to be able to get identity") + .expect("expected to get an identity for token mint operation"); + let identity_contract_nonce = contract_nonce_counter + .entry((operation_owner_id, contract.id())) + .or_default(); + *identity_contract_nonce += 1; + let token_transfer_transition: TokenTransferTransition = + TokenTransferTransitionV0 { + base: TokenBaseTransitionV0 { + identity_contract_nonce: *identity_contract_nonce, + token_contract_position: *token_pos, + data_contract_id: contract.id(), + token_id: *token_id, + using_group_info: None, + } + .into(), + amount: *amount, + recipient_id: *recipient, + public_note: public_note.clone(), + shared_encrypted_note: shared_encrypted_note.clone(), + private_encrypted_note: private_encrypted_note.clone(), + } + .into(); + + let batch_transition: BatchTransition = BatchTransitionV1 { + owner_id: identity.id, + transitions: vec![BatchedTransition::Token( + token_transfer_transition.into(), + )], + user_fee_increase: 0, + signature_public_key_id: 0, + signature: BinaryData::default(), + } + .into(); + + let mut batch_transition: StateTransition = batch_transition.into(); + + let identity_public_key = identity + .loaded_public_keys + .values() + .next() + .expect("expected a key"); + + batch_transition + .sign_external( + identity_public_key, + signer, + Some(|_data_contract_id, _document_type_name| { + Ok(SecurityLevel::HIGH) + }), + ) + .expect("expected to sign"); + + operations.push(batch_transition); + } _ => {} } } @@ -1553,7 +1734,7 @@ impl NetworkStrategy { ) } else { create_state_transitions_for_identities( - identities, + &mut identities, balance_range, signer, rng, diff --git a/packages/rs-drive-abci/tests/strategy_tests/token_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/token_tests.rs new file mode 100644 index 0000000000..484e517ece --- /dev/null +++ b/packages/rs-drive-abci/tests/strategy_tests/token_tests.rs @@ -0,0 +1,329 @@ +#[cfg(test)] +mod tests { + use crate::execution::run_chain_for_strategy; + use crate::strategy::NetworkStrategy; + use dpp::dash_to_duffs; + use dpp::data_contract::accessors::v0::DataContractV0Setters; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Setters; + use dpp::data_contract::DataContract; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::state_transition::StateTransition; + use dpp::tests::json_document::json_document_to_created_contract; + use dpp::tokens::token_event::TokenEvent; + use drive::query::PathQuery; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; + use drive_abci::test::helpers::setup::TestPlatformBuilder; + use platform_version::version::PlatformVersion; + use rand::prelude::StdRng; + use rand::SeedableRng; + use simple_signer::signer::SimpleSigner; + use strategy_tests::frequency::Frequency; + use strategy_tests::operations::{Operation, OperationType, TokenOp}; + use strategy_tests::transitions::create_state_transitions_for_identities; + use strategy_tests::{IdentityInsertInfo, StartIdentities, Strategy}; + + #[test] + fn run_chain_insert_one_new_identity_per_block_and_a_token_mint() { + let platform_version = PlatformVersion::latest(); + let mut created_contract = json_document_to_created_contract( + "tests/supporting_files/contract/basic-token/basic-token.json", + 1, + true, + platform_version, + ) + .expect("expected to get contract from a json document"); + + let mut rng = StdRng::seed_from_u64(567); + + let mut simple_signer = SimpleSigner::default(); + + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); + + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); + + simple_signer.add_keys(keys1); + simple_signer.add_keys(keys2); + + let start_identities: Vec<(Identity, Option)> = + create_state_transitions_for_identities( + vec![&mut identity1, &mut identity2], + &(dash_to_duffs!(1)..=dash_to_duffs!(1)), + &simple_signer, + &mut rng, + platform_version, + ) + .into_iter() + .map(|(identity, transition)| (identity, Some(transition))) + .collect(); + + let contract = created_contract.data_contract_mut(); + let mut token_configuration = contract + .token_configuration_mut(0) + .expect("expected to get token configuration"); + token_configuration.set_minting_allow_choosing_destination(true); + contract.set_owner_id(identity1.id()); + let new_id = DataContract::generate_data_contract_id_v0(identity1.id(), 1); + contract.set_id(new_id); + let token_id = contract.token_id(0).expect("expected to get token_id"); + + let token_op = TokenOp { + contract: contract.clone(), + token_id, + token_pos: 0, + use_identity_with_id: Some(identity1.id()), + action: TokenEvent::Mint(1000, identity2.id(), None), + }; + + let strategy = NetworkStrategy { + strategy: Strategy { + start_contracts: vec![(created_contract, None)], + operations: vec![Operation { + op_type: OperationType::Token(token_op), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }], + start_identities: StartIdentities { + hard_coded: start_identities.clone(), + ..Default::default() + }, + identity_inserts: IdentityInsertInfo::default(), + + identity_contract_nonce_gaps: None, + signer: Some(simple_signer), + }, + total_hpmns: 100, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: None, + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: true, + ..Default::default() + }; + let day_in_ms = 1000 * 60 * 60 * 24; + let config = PlatformConfig { + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + verify_sum_trees: true, + + ..Default::default() + }, + block_spacing_ms: day_in_ms, + testing_configs: PlatformTestConfig::default_minimal_verifications(), + ..Default::default() + }; + let block_count = 12; + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = + run_chain_for_strategy(&mut platform, block_count, strategy, config, 15, &mut None); + + let drive = &outcome.abci_app.platform.drive; + let identity_ids = vec![identity1.id().to_buffer(), identity2.id().to_buffer()]; + let balances = drive + .fetch_identities_token_balances( + token_id.to_buffer(), + identity_ids.as_slice(), + None, + platform_version, + ) + .expect("expected to get balances"); + + for (identity_id, token_balance) in balances { + assert!(token_balance.is_some()) + } + + let identity_1_token_balance = drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity1.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch"); + let identity_2_token_balance = drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch"); + + assert_eq!(identity_1_token_balance, Some(100000)); // The initial amount from creating the contract + assert_eq!(identity_2_token_balance, Some(11000)); // 11 blocks of 1000 + } + + #[test] + fn run_chain_insert_one_new_identity_per_block_and_a_token_transfer() { + let platform_version = PlatformVersion::latest(); + let mut created_contract = json_document_to_created_contract( + "tests/supporting_files/contract/basic-token/basic-token.json", + 1, + true, + platform_version, + ) + .expect("expected to get contract from a json document"); + + let mut rng = StdRng::seed_from_u64(567); + + let mut simple_signer = SimpleSigner::default(); + + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); + + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); + + simple_signer.add_keys(keys1); + simple_signer.add_keys(keys2); + + let start_identities: Vec<(Identity, Option)> = + create_state_transitions_for_identities( + vec![&mut identity1, &mut identity2], + &(dash_to_duffs!(1)..=dash_to_duffs!(1)), + &simple_signer, + &mut rng, + platform_version, + ) + .into_iter() + .map(|(identity, transition)| (identity, Some(transition))) + .collect(); + + let contract = created_contract.data_contract_mut(); + let mut token_configuration = contract + .token_configuration_mut(0) + .expect("expected to get token configuration"); + token_configuration.set_minting_allow_choosing_destination(true); + contract.set_owner_id(identity1.id()); + let new_id = DataContract::generate_data_contract_id_v0(identity1.id(), 1); + contract.set_id(new_id); + let token_id = contract.token_id(0).expect("expected to get token_id"); + + let token_op = TokenOp { + contract: contract.clone(), + token_id, + token_pos: 0, + use_identity_with_id: Some(identity1.id()), + action: TokenEvent::Transfer(identity2.id(), None, None, None, 1000), + }; + + let strategy = NetworkStrategy { + strategy: Strategy { + start_contracts: vec![(created_contract, None)], + operations: vec![Operation { + op_type: OperationType::Token(token_op), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }], + start_identities: StartIdentities { + hard_coded: start_identities.clone(), + ..Default::default() + }, + identity_inserts: IdentityInsertInfo::default(), + + identity_contract_nonce_gaps: None, + signer: Some(simple_signer), + }, + total_hpmns: 100, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: None, + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: true, + ..Default::default() + }; + let day_in_ms = 1000 * 60 * 60 * 24; + let config = PlatformConfig { + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + verify_sum_trees: true, + + ..Default::default() + }, + block_spacing_ms: day_in_ms, + testing_configs: PlatformTestConfig::default_minimal_verifications(), + ..Default::default() + }; + let block_count = 12; + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = + run_chain_for_strategy(&mut platform, block_count, strategy, config, 15, &mut None); + + let drive = &outcome.abci_app.platform.drive; + let identity_ids = vec![identity1.id().to_buffer(), identity2.id().to_buffer()]; + let balances = drive + .fetch_identities_token_balances( + token_id.to_buffer(), + identity_ids.as_slice(), + None, + platform_version, + ) + .expect("expected to get balances"); + + assert_eq!( + balances.get(&identity1.id()).copied(), + Some(Some(100000 - 11000)) + ); + assert_eq!(balances.get(&identity2.id()).copied(), Some(Some(11000))); + + // Let's also try this fetching + + let identity_1_token_balance = drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity1.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch"); + let identity_2_token_balance = drive + .fetch_identity_token_balance( + token_id.to_buffer(), + identity2.id().to_buffer(), + None, + platform_version, + ) + .expect("expected to fetch"); + + assert_eq!(identity_1_token_balance, Some(100000 - 11000)); // The initial amount from creating the contract less 11 times 1000 that we transferred + assert_eq!(identity_2_token_balance, Some(11000)); // 11 blocks of 1000 + } +} 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 57f347f977..64701edcfa 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 @@ -15,24 +15,29 @@ use dpp::version::PlatformVersion; use drive::drive::identity::key::fetch::IdentityKeysRequest; use drive::drive::Drive; use drive::query::{SingleDocumentDriveQuery, SingleDocumentDriveQueryContestedStatus}; -use drive::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use drive::state_transition_action::StateTransitionAction; use drive_abci::execution::validation::state_transition::transformer::StateTransitionActionTransformerV0; use drive_abci::platform_types::platform::PlatformRef; use drive_abci::rpc::core::MockCoreRPCLike; use tenderdash_abci::proto::abci::ExecTxResult; - -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0Getters; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::data_contracts::SystemDataContract; +use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; +use dpp::prelude::Identifier; use dpp::voting::votes::Vote; use drive::drive::votes::resolved::vote_polls::ResolvedVotePoll; use drive::drive::votes::resolved::votes::resolved_resource_vote::accessors::v0::ResolvedResourceVoteGettersV0; use drive::drive::votes::resolved::votes::ResolvedVote; -use drive::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionActionAccessorsV0, DocumentFromCreateTransitionAction}; -use drive::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::DocumentFromReplaceTransitionAction; -use drive::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::DocumentTransferTransitionActionAccessorsV0; -use drive::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use drive::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionActionAccessorsV0, DocumentFromCreateTransitionAction}; +use drive::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; +use drive::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::DocumentFromReplaceTransitionAction; +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::token_transition::token_base_transition_action::TokenBaseTransitionActionAccessorsV0; use drive_abci::abci::app::FullAbciApplication; use drive_abci::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use drive_abci::execution::validation::state_transition::ValidationMode; @@ -59,11 +64,11 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( .iter() .enumerate() .map(|(num, (state_transition, result))| { - if let StateTransition::DocumentsBatch(batch) = state_transition { - let _first = batch.transitions().first().unwrap(); - - // dbg!(batch.transitions().len(), hex::encode(first.base().id()), state.height(), first.to_string()); - } + // if let StateTransition::DocumentsBatch(batch) = state_transition { + // let _first = batch.document_transitions().first().unwrap(); + // + // // dbg!(batch.transitions().len(), hex::encode(first.base().id()), state.height(), first.to_string()); + // } let mut execution_context = StateTransitionExecutionContext::default_for_platform_version(platform_version) @@ -209,59 +214,87 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( ); } } - StateTransitionAction::DocumentsBatchAction(documents_batch_transition) => { - documents_batch_transition + StateTransitionAction::BatchAction(batch_transition) => { + batch_transition .transitions() .iter() - .for_each(|transition| { - let document_contested_status = - if let DocumentTransitionAction::CreateAction(create_action) = - transition - { - if create_action.prefunded_voting_balance().is_some() { - SingleDocumentDriveQueryContestedStatus::Contested as u8 + .for_each(|transition| match transition { + BatchedTransitionAction::DocumentAction(document_transition_action) => { + let document_contested_status = + if let DocumentTransitionAction::CreateAction(create_action) = + document_transition_action + { + if create_action.prefunded_voting_balance().is_some() { + SingleDocumentDriveQueryContestedStatus::Contested as u8 + } else { + SingleDocumentDriveQueryContestedStatus::NotContested + as u8 + } } else { SingleDocumentDriveQueryContestedStatus::NotContested as u8 - } - } else { - SingleDocumentDriveQueryContestedStatus::NotContested as u8 - }; - proofs_request - .documents - .push(get_proofs_request_v0::DocumentRequest { - contract_id: transition - .base() - .expect("expected a base for the document transition") - .data_contract_id() - .to_vec(), - document_type: transition - .base() - .expect("expected a base for the document transition") - .document_type_name() - .clone(), - document_type_keeps_history: transition - .base() - .expect("expected a base for the document transition") - .data_contract_fetch_info() - .contract - .document_type_for_name( - transition - .base() - .expect( - "expected a base for the document transition", + }; + proofs_request.documents.push( + get_proofs_request_v0::DocumentRequest { + contract_id: document_transition_action + .base() + .data_contract_id() + .to_vec(), + document_type: document_transition_action + .base() + .document_type_name() + .clone(), + document_type_keeps_history: document_transition_action + .base() + .data_contract_fetch_info() + .contract + .document_type_for_name( + document_transition_action + .base() + .document_type_name() + .as_str(), + ) + .expect("get document type") + .documents_keep_history(), + document_id: document_transition_action + .base() + .id() + .to_vec(), + document_contested_status: document_contested_status as i32, + }, + ); + } + BatchedTransitionAction::TokenAction(token_transition_action) => { + if token_transition_action + .base() + .token_configuration() + .expect("expected token configuration") + .keeps_history() + { + // if we keep history we just need to check the historical document + proofs_request.documents.push( + get_proofs_request_v0::DocumentRequest { + contract_id: SystemDataContract::TokenHistory + .id() + .to_vec(), + document_type: token_transition_action + .historical_document_type_name() + .to_string(), + document_type_keeps_history: false, + document_id: token_transition_action + .historical_document_id( + batch_transition.owner_id(), + token_transition_action + .base() + .identity_contract_nonce(), ) - .document_type_name() - .as_str(), - ) - .expect("get document type") - .documents_keep_history(), - document_id: transition - .base() - .expect("expected a base for the document transition") - .id() - .to_vec(), - document_contested_status: document_contested_status as i32, - }); + .to_vec(), + document_contested_status: 0, + }, + ); + } else { + } + } + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => {} }); let versioned_request = GetProofsRequest { version: Some(get_proofs_request::Version::V0(proofs_request)), @@ -274,211 +307,295 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( let response_proof = response.proof_owned().expect("proof should be present"); - for document_transition_action in - documents_batch_transition.transitions().iter() - { - let contract_fetch_info = document_transition_action - .base() - .expect("expected a base for the document transition") - .data_contract_fetch_info(); - - let document_type = contract_fetch_info - .contract - .document_type_for_name( - document_transition_action - .base() - .expect("expected a base for the document transition") - .document_type_name() - .as_str(), - ) - .expect("get document type"); - let contested_status = - if let DocumentTransitionAction::CreateAction(create_action) = - document_transition_action - { - if create_action.prefunded_voting_balance().is_some() { - SingleDocumentDriveQueryContestedStatus::Contested - } else { - SingleDocumentDriveQueryContestedStatus::NotContested - } - } else { - SingleDocumentDriveQueryContestedStatus::NotContested - }; - - let query = SingleDocumentDriveQuery { - contract_id: document_transition_action - .base() - .expect("expected a base for the document transition") - .data_contract_id() - .into_buffer(), - document_type_name: document_transition_action - .base() - .expect("expected a base for the document transition") - .document_type_name() - .clone(), - document_type_keeps_history: document_type.documents_keep_history(), - document_id: document_transition_action - .base() - .expect("expected a base for the document transition") - .id() - .into_buffer(), - block_time_ms: None, //None because we want latest - contested_status, - }; - - // dbg!( - // platform.state.height(), - // document_transition_action.action_type(), - // document_transition_action - // .base() - // .id() - // .to_string(Encoding::Base58) - // ); - - let (root_hash, document) = query - .verify_proof( - false, - &response_proof.grovedb_proof, - document_type, - platform_version, - ) - .expect("expected to verify a document"); + for transition_action in batch_transition.transitions().iter() { + match transition_action { + BatchedTransitionAction::DocumentAction(document_action) => { + let contract_fetch_info = + document_action.base().data_contract_fetch_info(); + + let document_type = contract_fetch_info + .contract + .document_type_for_name( + document_action.base().document_type_name().as_str(), + ) + .expect("get document type"); + let contested_status = + if let DocumentTransitionAction::CreateAction(create_action) = + document_action + { + if create_action.prefunded_voting_balance().is_some() { + SingleDocumentDriveQueryContestedStatus::Contested + } else { + SingleDocumentDriveQueryContestedStatus::NotContested + } + } else { + SingleDocumentDriveQueryContestedStatus::NotContested + }; - assert_eq!( - &root_hash, - expected_root_hash, - "state last block info {:?}", - platform.state.last_committed_block_info() - ); + let query = SingleDocumentDriveQuery { + contract_id: document_action + .base() + .data_contract_id() + .into_buffer(), + document_type_name: document_action + .base() + .document_type_name() + .clone(), + document_type_keeps_history: document_type + .documents_keep_history(), + document_id: document_action.base().id().into_buffer(), + block_time_ms: None, //None because we want latest + contested_status, + }; - match document_transition_action { - DocumentTransitionAction::CreateAction(creation_action) => { - if *was_executed { - let document = document.unwrap_or_else(|| { - panic!( - "expected a document on block {}", - platform.state.last_committed_block_height() - ) - }); - // dbg!( - // &document, - // Document::try_from_create_transition( - // creation_action, - // documents_batch_transition.owner_id(), - // platform_version, - // ) - // .expect("expected to get document") - // ); - assert_eq!( - document, - Document::try_from_create_transition_action( - creation_action, - documents_batch_transition.owner_id(), - platform_version, - ) - .expect("expected to get document") - ); - } else { - //there is the possibility that the state transition was not executed because it already existed, - // we can discount that for now in tests - assert!(document.is_none()); - } - } - DocumentTransitionAction::ReplaceAction(replace_action) => { - if *was_executed { - // it's also possible we deleted something we replaced - if let Some(document) = document { - assert_eq!( - document, - Document::try_from_replace_transition_action( - replace_action, - documents_batch_transition.owner_id(), - platform_version, - ) - .expect("expected to get document") - ); + // dbg!( + // platform.state.height(), + // document_transition_action.action_type(), + // document_transition_action + // .base() + // .id() + // .to_string(Encoding::Base58) + // ); + + let (root_hash, document) = query + .verify_proof( + false, + &response_proof.grovedb_proof, + document_type, + platform_version, + ) + .expect("expected to verify a document"); + + assert_eq!( + &root_hash, + expected_root_hash, + "state last block info {:?}", + platform.state.last_committed_block_info() + ); + + match document_action { + DocumentTransitionAction::CreateAction(creation_action) => { + if *was_executed { + let document = document.unwrap_or_else(|| { + panic!( + "expected a document on block {}", + platform.state.last_committed_block_height() + ) + }); + // dbg!( + // &document, + // Document::try_from_create_transition( + // creation_action, + // documents_batch_transition.owner_id(), + // platform_version, + // ) + // .expect("expected to get document") + // ); + assert_eq!( + document, + Document::try_from_create_transition_action( + creation_action, + batch_transition.owner_id(), + platform_version, + ) + .expect("expected to get document") + ); + } else { + //there is the possibility that the state transition was not executed because it already existed, + // we can discount that for now in tests + assert!(document.is_none()); + } } - } else { - //there is the possibility that the state transition was not executed and the state is equal to the previous - // state, aka there would have been no change anyways, we can discount that for now - if let Some(document) = document { - assert_ne!( - document, - Document::try_from_replace_transition_action( - replace_action, - documents_batch_transition.owner_id(), - platform_version, - ) - .expect("expected to get document") - ); + DocumentTransitionAction::ReplaceAction(replace_action) => { + if *was_executed { + // it's also possible we deleted something we replaced + if let Some(document) = document { + assert_eq!( + document, + Document::try_from_replace_transition_action( + replace_action, + batch_transition.owner_id(), + platform_version, + ) + .expect("expected to get document") + ); + } + } else { + //there is the possibility that the state transition was not executed and the state is equal to the previous + // state, aka there would have been no change anyways, we can discount that for now + if let Some(document) = document { + assert_ne!( + document, + Document::try_from_replace_transition_action( + replace_action, + batch_transition.owner_id(), + platform_version, + ) + .expect("expected to get document") + ); + } + } } - } - } - DocumentTransitionAction::DeleteAction(_) => { - // we expect no document - assert!(document.is_none()); - } - DocumentTransitionAction::BumpIdentityDataContractNonce(_) => { - panic!("we should not have a bump identity data contract nonce"); - } - DocumentTransitionAction::TransferAction(transfer_action) => { - if *was_executed { - // it's also possible we deleted something we replaced - if let Some(document) = document { - assert_eq!( - document.owner_id(), - transfer_action.document().owner_id() - ); + DocumentTransitionAction::DeleteAction(_) => { + // we expect no document + assert!(document.is_none()); } - } else { - //there is the possibility that the state transition was not executed and the state is equal to the previous - // state, aka there would have been no change anyways, we can discount that for now - if let Some(document) = document { - assert_ne!( - document.owner_id(), - transfer_action.document().owner_id() - ); + DocumentTransitionAction::TransferAction(transfer_action) => { + if *was_executed { + // it's also possible we deleted something we replaced + if let Some(document) = document { + assert_eq!( + document.owner_id(), + transfer_action.document().owner_id() + ); + } + } else { + //there is the possibility that the state transition was not executed and the state is equal to the previous + // state, aka there would have been no change anyways, we can discount that for now + if let Some(document) = document { + assert_ne!( + document.owner_id(), + transfer_action.document().owner_id() + ); + } + } } - } - } - DocumentTransitionAction::PurchaseAction(purchase_action) => { - if *was_executed { - if let Some(document) = document { - assert_eq!( - document.owner_id(), - purchase_action.document().owner_id() - ); + DocumentTransitionAction::PurchaseAction(purchase_action) => { + if *was_executed { + if let Some(document) = document { + assert_eq!( + document.owner_id(), + purchase_action.document().owner_id() + ); + } + } else { + //there is the possibility that the state transition was not executed and the state is equal to the previous + // state, aka there would have been no change anyways, we can discount that for now + if let Some(document) = document { + assert_ne!( + document.owner_id(), + purchase_action.document().owner_id() + ); + } + } } - } else { - //there is the possibility that the state transition was not executed and the state is equal to the previous - // state, aka there would have been no change anyways, we can discount that for now - if let Some(document) = document { - assert_ne!( - document.owner_id(), - purchase_action.document().owner_id() - ); + DocumentTransitionAction::UpdatePriceAction( + update_price_action, + ) => { + if *was_executed { + if let Some(document) = document { + assert_eq!( + document.get(PRICE), + update_price_action.document().get(PRICE) + ); + } + } else { + //there is the possibility that the state transition was not executed and the state is equal to the previous + // state, aka there would have been no change anyways, we can discount that for now + if let Some(document) = document { + assert_ne!( + document.get(PRICE), + update_price_action.document().get(PRICE) + ); + } + } } } } - DocumentTransitionAction::UpdatePriceAction(update_price_action) => { - if *was_executed { - if let Some(document) = document { - assert_eq!( - document.get(PRICE), - update_price_action.document().get(PRICE) - ); - } + BatchedTransitionAction::TokenAction(token_transition_action) => { + if token_transition_action + .base() + .token_configuration() + .expect("expected token configuration") + .keeps_history() + { + let token_id = token_transition_action.base().token_id(); + let document_type_name = token_transition_action + .historical_document_type_name() + .to_string(); + + let token_history = platform + .drive + .cache + .system_data_contracts + .load_token_history(); + + let query = SingleDocumentDriveQuery { + contract_id: SystemDataContract::TokenHistory + .id() + .to_buffer(), + document_type_name, + document_type_keeps_history: false, + document_id: token_transition_action + .historical_document_id( + batch_transition.owner_id(), + token_transition_action + .base() + .identity_contract_nonce(), + ) + .to_buffer(), + block_time_ms: None, //None because we want latest + contested_status: + SingleDocumentDriveQueryContestedStatus::NotContested, + }; + + let (root_hash, serialized_document) = query + .verify_proof_keep_serialized( + false, + &response_proof.grovedb_proof, + platform_version, + ) + .expect("expected to verify a document"); + + assert_eq!( + &root_hash, + expected_root_hash, + "state last block info {:?}", + platform.state.last_committed_block_info() + ); + + assert!( + serialized_document.is_some(), + "we expect a token history document" + ); + + let expected_document = token_transition_action + .build_historical_document( + &token_history, + token_id, + batch_transition.owner_id(), + token_transition_action + .base() + .identity_contract_nonce(), + platform + .state + .last_committed_block_info() + .as_ref() + .expect("expected last commited block info") + .basic_info(), + ) + .expect("expected to build historical document"); + + let serialized_expected_document = expected_document + .serialize( + token_transition_action + .historical_document_type(&token_history) + .expect("expected document type"), + platform_version, + ) + .expect("expected to serialize"); + + assert_eq!( + serialized_document.unwrap(), + serialized_expected_document + ); } else { - //there is the possibility that the state transition was not executed and the state is equal to the previous - // state, aka there would have been no change anyways, we can discount that for now - if let Some(document) = document { - assert_ne!( - document.get(PRICE), - update_price_action.document().get(PRICE) - ); - } + todo!(); } } + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { + panic!("we should not have a bump identity data contract nonce"); + } } } } diff --git a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs index 3547f94c80..d0e804dfa9 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs @@ -70,19 +70,16 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1], + vec![&mut identity1], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, @@ -316,7 +313,7 @@ mod tests { .first() .expect("expected a document insert"); - assert_matches!(state_transition, StateTransition::DocumentsBatch(_)); + assert_matches!(state_transition, StateTransition::Batch(_)); assert_eq!(execution_result.code, 0); } @@ -348,29 +345,23 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, @@ -624,29 +615,23 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, @@ -981,29 +966,23 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, @@ -1351,29 +1330,23 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, @@ -1755,29 +1728,23 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, @@ -2168,29 +2135,23 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys1) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys1) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys1); - let (identity2, keys2) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys2) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys2); let start_identities: Vec<(Identity, Option)> = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &simple_signer, &mut rng, 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 new file mode 100644 index 0000000000..7f103653d8 --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/basic-token/basic-token.json @@ -0,0 +1,18 @@ +{ + "$format_version": "1", + "id": "EbL1zYg1JrpPX9rYbASihRsSEgwKbqZAJu6B1Z2SKKU2", + "ownerId": "F1Ue2M5PfDjDX69NqrZdChdEbwF2SYZ8UF4qNjsCQu1d", + "version": 1, + "documentSchemas": {}, + "tokens": { + "0": { + "$format_version": "0", + "conventions": { + "decimals": 8 + }, + "baseSupply": 100000, + "maxSupply": null, + "keepsHistory": true + } + } +} \ No newline at end of file diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json new file mode 100644 index 0000000000..3a1c2daecc --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json @@ -0,0 +1,135 @@ +{ + "$format_version": "0", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "creationRestrictionMode": 1, + "properties": { + "name": { + "type": "string", + "description": "Name of the card", + "maxLength": 63, + "position": 0 + }, + "description": { + "type": "string", + "description": "Description of the card", + "maxLength": 256, + "position": 1 + }, + "imageUrl": { + "type": "string", + "description": "URL of the image associated with the card", + "maxLength": 2048, + "format": "uri", + "position": 2 + }, + "imageHash": { + "type": "array", + "description": "SHA256 hash of the bytes of the image specified by imageUrl", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "position": 3 + }, + "imageFingerprint": { + "type": "array", + "description": "dHash of the image specified by imageUrl", + "byteArray": true, + "minItems": 8, + "maxItems": 8, + "position": 4 + }, + "attack": { + "type": "integer", + "description": "Attack power of the card", + "minimum": 0, + "position": 5 + }, + "defense": { + "type": "integer", + "description": "Defense level of the card", + "minimum": 0, + "position": 6 + } + }, + "indices": [ + { + "name": "owner", + "properties": [ + { + "$ownerId": "asc" + } + ] + }, + { + "name": "attack", + "properties": [ + { + "attack": "asc" + } + ] + }, + { + "name": "defense", + "properties": [ + { + "defense": "asc" + } + ] + }, + { + "name": "transferredAt", + "properties": [ + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "ownerTransferredAt", + "properties": [ + { + "$ownerId": "asc" + }, + { + "$transferredAt": "asc" + } + ] + }, + { + "name": "transferredAtBlockHeight", + "properties": [ + { + "$transferredAtBlockHeight": "asc" + } + ] + }, + { + "name": "transferredAtCoreBlockHeight", + "properties": [ + { + "$transferredAtCoreBlockHeight": "asc" + } + ] + } + ], + "required": [ + "name", + "$transferredAt", + "$transferredAtBlockHeight", + "$transferredAtCoreBlockHeight", + "attack", + "defense" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 46e32521d9..9b140c4e55 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 = { version = "2.2.1", optional = true, default-features = false } -grovedb-costs = { version = "2.2.1", optional = true } -grovedb-path = { version = "2.2.1" } -grovedb-storage = { version = "2.2.1", optional = true } -grovedb-version = { version = "2.2.1" } -grovedb-epoch-based-storage-flags = { version = "2.2.1" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } [dev-dependencies] criterion = "0.5" @@ -100,6 +100,7 @@ server = [ "parking_lot", "arc-swap", "moka", + "dpp/validation", "dpp/platform-value-json", "dpp/system_contracts", "dpp/state-transitions", diff --git a/packages/rs-drive/src/cache/system_contracts.rs b/packages/rs-drive/src/cache/system_contracts.rs index c1a2785c3c..7de44da36b 100644 --- a/packages/rs-drive/src/cache/system_contracts.rs +++ b/packages/rs-drive/src/cache/system_contracts.rs @@ -15,6 +15,8 @@ pub struct SystemDataContracts { dashpay: ArcSwap, /// Masternode reward shares contract masternode_reward_shares: ArcSwap, + /// Token history contract + token_history: ArcSwap, } impl SystemDataContracts { @@ -39,6 +41,10 @@ impl SystemDataContracts { SystemDataContract::MasternodeRewards, platform_version, )?), + token_history: ArcSwap::from_pointee(load_system_data_contract( + SystemDataContract::TokenHistory, + platform_version, + )?), }) } @@ -47,6 +53,11 @@ impl SystemDataContracts { self.withdrawals.load() } + /// Returns token history contract + pub fn load_token_history(&self) -> Guard> { + self.token_history.load() + } + /// Returns DPNS contract pub fn load_dpns(&self) -> Guard> { self.dpns.load() diff --git a/packages/rs-drive/src/drive/asset_lock/estimation_costs/add_estimation_costs_for_adding_asset_lock/v0/mod.rs b/packages/rs-drive/src/drive/asset_lock/estimation_costs/add_estimation_costs_for_adding_asset_lock/v0/mod.rs index 1110b44844..1d8cb180ee 100644 --- a/packages/rs-drive/src/drive/asset_lock/estimation_costs/add_estimation_costs_for_adding_asset_lock/v0/mod.rs +++ b/packages/rs-drive/src/drive/asset_lock/estimation_costs/add_estimation_costs_for_adding_asset_lock/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::asset_lock::asset_lock_storage_path; use grovedb::EstimatedSumTrees::SomeSumTrees; @@ -61,12 +61,15 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(3, false), estimated_layer_sizes: AllSubtrees( 12, // 32 + 1 + 1 / 3 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, @@ -77,7 +80,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(asset_lock_storage_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems( 36, //The size of an outpoint diff --git a/packages/rs-drive/src/drive/asset_lock/fetch_asset_lock_outpoint_info/v0/mod.rs b/packages/rs-drive/src/drive/asset_lock/fetch_asset_lock_outpoint_info/v0/mod.rs index eb929eda17..c85e0dc84d 100644 --- a/packages/rs-drive/src/drive/asset_lock/fetch_asset_lock_outpoint_info/v0/mod.rs +++ b/packages/rs-drive/src/drive/asset_lock/fetch_asset_lock_outpoint_info/v0/mod.rs @@ -13,7 +13,7 @@ use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; use dpp::asset_lock::StoredAssetLockInfo; use dpp::platform_value::Bytes36; use dpp::serialization::PlatformDeserializable; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Checks if a given `outpoint` is present as an asset lock in the transaction. @@ -68,7 +68,7 @@ impl Drive { StatefulDirectQuery } else { StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, query_target: QueryTargetValue(36), } }; diff --git a/packages/rs-drive/src/drive/balances/mod.rs b/packages/rs-drive/src/drive/balances/mod.rs index 39f15f4298..23c74cd12a 100644 --- a/packages/rs-drive/src/drive/balances/mod.rs +++ b/packages/rs-drive/src/drive/balances/mod.rs @@ -22,10 +22,14 @@ use crate::drive::RootTree; use crate::query::Query; use grovedb::{PathQuery, SizedQuery}; -/// Storage fee pool key +/// Total system credits storage #[cfg(any(feature = "server", feature = "verify"))] pub const TOTAL_SYSTEM_CREDITS_STORAGE_KEY: &[u8; 1] = b"D"; +/// Total token supplies storage +#[cfg(any(feature = "server", feature = "verify"))] +pub const TOTAL_TOKEN_SUPPLIES_STORAGE_KEY: &[u8; 1] = b"T"; + /// The path for all the credits in the system #[cfg(any(feature = "server", feature = "verify"))] pub fn total_credits_path() -> [&'static [u8]; 2] { @@ -57,6 +61,60 @@ pub fn total_credits_on_platform_path_query() -> PathQuery { } } +/// The path for the root of all token supplies +#[cfg(any(feature = "server", feature = "verify"))] +pub fn total_tokens_root_supply_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::Misc), + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY, + ] +} + +/// The path as a vec for the root of all token supplies +#[cfg(any(feature = "server", feature = "verify"))] +pub fn total_tokens_root_supply_path_vec() -> Vec> { + vec![ + vec![RootTree::Misc as u8], + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY.to_vec(), + ] +} + +/// The path for the token supply for a given token +#[cfg(any(feature = "server", feature = "verify"))] +pub fn total_token_supply_path(token_id: &[u8; 32]) -> [&[u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::Misc), + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY, + token_id, + ] +} + +/// The path as a vec for the token supply for a given token +#[cfg(any(feature = "server", feature = "verify"))] +pub fn total_token_supply_path_vec(token_id: [u8; 32]) -> Vec> { + vec![ + vec![RootTree::Misc as u8], + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY.to_vec(), + token_id.to_vec(), + ] +} + +/// A path query helper to get the total token supply for a given token on Platform +#[cfg(any(feature = "server", feature = "verify"))] +pub fn total_supply_for_token_on_platform_path_query(token_id: [u8; 32]) -> PathQuery { + PathQuery { + path: vec![ + vec![RootTree::Misc as u8], + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY.to_vec(), + ], + query: SizedQuery { + query: Query::new_single_key(token_id.to_vec()), + limit: Some(1), + offset: None, + }, + } +} + /// The path for the balances tree #[cfg(any(feature = "server", feature = "verify"))] pub(crate) fn balance_path() -> [&'static [u8]; 1] { diff --git a/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs b/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs index 816b660e32..8a7289995e 100644 --- a/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/apply/apply_contract_with_serialization/v0/mod.rs @@ -18,7 +18,7 @@ use dpp::serialization::PlatformDeserializableWithPotentialValidationFromVersion use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::borrow::Cow; use std::collections::HashMap; @@ -99,7 +99,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, // we can ignore flags as this is just an approximation // and it's doubtful that contracts will always be inserted at max size query_target: QueryTargetValue( @@ -208,6 +208,7 @@ impl Drive { block_info, estimated_costs_only_with_layer_info, &mut drive_operations, + transaction, platform_version, )?; } diff --git a/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs b/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs index ba04d65bc6..c1acab1802 100644 --- a/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/estimation_costs/add_estimation_costs_for_contract_insertion/v0/mod.rs @@ -16,9 +16,9 @@ use crate::util::type_constants::{DEFAULT_FLOAT_SIZE, DEFAULT_FLOAT_SIZE_U8}; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, EstimatedLevel}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllSubtrees, Mix}; use grovedb::EstimatedSumTrees::NoSumTrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; impl Drive { @@ -61,7 +61,7 @@ impl Drive { ), ), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(2), estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_INDEX_NAME_SIZE, @@ -80,7 +80,7 @@ impl Drive { document_type_name.as_str(), )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(0, true), estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_INDEX_NAME_SIZE, @@ -103,7 +103,7 @@ impl Drive { contract.id_ref().as_bytes(), )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(AVERAGE_NUMBER_OF_UPDATES as u32), estimated_layer_sizes: Mix { subtrees_size: None, diff --git a/packages/rs-drive/src/drive/contract/insert/add_contract_to_storage/v0/mod.rs b/packages/rs-drive/src/drive/contract/insert/add_contract_to_storage/v0/mod.rs index 8844fe39bc..07e33e9be1 100644 --- a/packages/rs-drive/src/drive/contract/insert/add_contract_to_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/insert/add_contract_to_storage/v0/mod.rs @@ -19,7 +19,7 @@ use dpp::version::drive_versions::DriveVersion; use grovedb::batch::key_info::KeyInfo; use grovedb::batch::KeyInfoPath; use grovedb::reference_path::ReferencePathType::SiblingReference; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -64,8 +64,8 @@ impl Drive { } else { let apply_type = if estimated_costs_only_with_layer_info.is_some() { BatchInsertTreeApplyType::StatelessBatchInsertTree { - is_sum_tree: false, - in_tree_using_sums: false, + tree_type: TreeType::NormalTree, + in_tree_type: TreeType::NormalTree, flags_len: storage_flags .as_ref() .map(|flags| flags.to_element_flags().len()) @@ -79,7 +79,7 @@ impl Drive { self.batch_insert_empty_tree_if_not_exists( key_info, - false, + TreeType::NormalTree, storage_flags.as_ref().map(|flags| flags.as_ref()), apply_type, transaction, diff --git a/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs b/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs index 8b39715cbb..9d6eac5437 100644 --- a/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs +++ b/packages/rs-drive/src/drive/contract/insert/insert_contract/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -51,9 +52,12 @@ impl Drive { 0 => { self.insert_contract_v0(contract, block_info, apply, transaction, platform_version) } + 1 => { + self.insert_contract_v1(contract, block_info, apply, transaction, platform_version) + } version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "insert_contract".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } @@ -86,6 +90,7 @@ impl Drive { HashMap, >, drive_operations: &mut Vec, + transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result<(), Error> { match platform_version @@ -103,9 +108,18 @@ impl Drive { drive_operations, platform_version, ), + 1 => self.insert_contract_add_operations_v1( + contract_element, + contract, + block_info, + estimated_costs_only_with_layer_info, + drive_operations, + transaction, + platform_version, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "insert_contract_add_operations".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/mod.rs b/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/mod.rs index 207626f064..635e315e86 100644 --- a/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/insert/insert_contract/v0/mod.rs @@ -145,7 +145,7 @@ impl Drive { /// The operations for adding a contract. /// These operations add a contract to storage using `add_contract_to_storage` /// and insert the empty trees which will be necessary to later insert documents. - fn insert_contract_operations_v0( + pub(in crate::drive::contract::insert::insert_contract) fn insert_contract_operations_v0( &self, contract_element: Element, contract: &DataContract, diff --git a/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs b/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs new file mode 100644 index 0000000000..29c49b6750 --- /dev/null +++ b/packages/rs-drive/src/drive/contract/insert/insert_contract/v1/mod.rs @@ -0,0 +1,278 @@ +use crate::drive::Drive; +use crate::util::storage_flags::StorageFlags; + +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::config::v0::DataContractConfigGettersV0; +use dpp::data_contract::DataContract; +use dpp::fee::fee_result::FeeResult; + +use crate::drive::balances::total_tokens_root_supply_path_vec; +use crate::drive::tokens::paths::{ + token_balances_path_vec, token_balances_root_path, token_identity_infos_root_path, +}; +use crate::error::contract::DataContractError; +use crate::util::object_size_info::DriveKeyInfo; +use crate::util::object_size_info::PathKeyElementInfo::PathKeyElement; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::serialization::PlatformSerializableWithPlatformVersion; +use dpp::version::PlatformVersion; +use dpp::ProtocolError; +use grovedb::batch::KeyInfoPath; +use grovedb::Element::SumItem; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Insert a contract. + #[inline(always)] + pub(super) fn insert_contract_v1( + &self, + contract: &DataContract, + block_info: BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations: Vec = vec![]; + + let storage_flags = if contract.config().can_be_deleted() || !contract.config().readonly() { + Some(StorageFlags::new_single_epoch( + block_info.epoch.index, + Some(contract.owner_id().to_buffer()), + )) + } else { + None + }; + + let serialized_contract = + contract.serialize_to_bytes_with_platform_version(platform_version)?; + + if serialized_contract.len() as u64 > u32::MAX as u64 + || serialized_contract.len() as u32 + > platform_version.dpp.contract_versions.max_serialized_size + { + // This should normally be caught by DPP, but there is a rare possibility that the + // re-serialized size is bigger than the original serialized data contract. + return Err(Error::DataContract(DataContractError::ContractTooBig(format!("Trying to insert a data contract of size {} that is over the max allowed insertion size {}", serialized_contract.len(), platform_version.dpp.contract_versions.max_serialized_size)))); + } + + let contract_element = Element::Item( + serialized_contract, + StorageFlags::map_to_some_element_flags(storage_flags.as_ref()), + ); + + self.insert_contract_element_v1( + contract_element, + contract, + &block_info, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + ) + } + + /// Adds a contract to storage using `add_contract_to_storage` + /// and inserts the empty trees which will be necessary to later insert documents. + fn insert_contract_element_v1( + &self, + contract_element: Element, + contract: &DataContract, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + let batch_operations = self.insert_contract_operations_v1( + contract_element, + contract, + block_info, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// The operations for adding a contract. + /// These operations add a contract to storage using `add_contract_to_storage` + /// and insert the empty trees which will be necessary to later insert documents. + #[inline(always)] + pub(super) fn insert_contract_add_operations_v1( + &self, + contract_element: Element, + contract: &DataContract, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + drive_operations: &mut Vec, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let batch_operations = self.insert_contract_operations_v1( + contract_element, + contract, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + drive_operations.extend(batch_operations); + Ok(()) + } + + /// The operations for adding a contract. + /// These operations add a contract to storage using `add_contract_to_storage` + /// and insert the empty trees which will be necessary to later insert documents. + fn insert_contract_operations_v1( + &self, + contract_element: Element, + contract: &DataContract, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = self + .insert_contract_operations_v0( + contract_element, + contract, + block_info, + estimated_costs_only_with_layer_info, + platform_version, + )?; + + for (token_pos, token_config) in contract.tokens() { + let token_id = contract.token_id(*token_pos).ok_or(Error::DataContract( + DataContractError::CorruptedDataContract(format!( + "data contract has a token at position {}, but can not find it", + token_pos + )), + ))?; + + let token_id_bytes = token_id.to_buffer(); + + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info + { + Drive::add_estimation_costs_for_token_balances( + token_id_bytes, + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + Drive::add_estimation_costs_for_token_identity_infos( + token_id_bytes, + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + Drive::add_estimation_costs_for_token_total_supply( + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + self.batch_insert_empty_sum_tree( + token_balances_root_path(), + DriveKeyInfo::KeyRef(token_id_bytes.as_slice()), + None, + &mut batch_operations, + &platform_version.drive, + )?; + + self.batch_insert_empty_tree( + token_identity_infos_root_path(), + DriveKeyInfo::KeyRef(token_id_bytes.as_slice()), + None, + &mut batch_operations, + &platform_version.drive, + )?; + + let path_holding_total_token_supply = total_tokens_root_supply_path_vec(); + + if token_config.base_supply() > 0 { + // We have a base supply that needs to be distributed on contract creation + let destination_identity_id = token_config + .new_tokens_destination_identity() + .unwrap_or(contract.owner_id()); + let token_balance_path = token_balances_path_vec(token_id_bytes); + + if token_config.base_supply() > i64::MAX as u64 { + return Err( + ProtocolError::CriticalCorruptedCreditsCodeExecution(format!( + "Token base supply over i64 max, is {}", + token_config.base_supply() + )) + .into(), + ); + } + self.batch_insert::<0>( + PathKeyElement(( + token_balance_path, + destination_identity_id.to_vec(), + Element::new_sum_item(token_config.base_supply() as i64), + )), + &mut batch_operations, + &platform_version.drive, + )?; + self.batch_insert::<0>( + PathKeyElement(( + path_holding_total_token_supply, + token_id.to_vec(), + Element::new_sum_item(token_config.base_supply() as i64), + )), + &mut batch_operations, + &platform_version.drive, + )?; + } else { + self.batch_insert::<0>( + PathKeyElement(( + path_holding_total_token_supply, + token_id.to_vec(), + SumItem(0, None), + )), + &mut batch_operations, + &platform_version.drive, + )?; + } + } + + if !contract.groups().is_empty() { + batch_operations.extend(self.add_new_groups_operations( + contract.id(), + contract.groups(), + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + } + + Ok(batch_operations) + } +} diff --git a/packages/rs-drive/src/drive/contract/update/update_contract/mod.rs b/packages/rs-drive/src/drive/contract/update/update_contract/mod.rs index 8d22fc4043..f9f682d74a 100644 --- a/packages/rs-drive/src/drive/contract/update/update_contract/mod.rs +++ b/packages/rs-drive/src/drive/contract/update/update_contract/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -64,9 +65,17 @@ impl Drive { platform_version, previous_fee_versions, ), + 1 => self.update_contract_v1( + contract, + block_info, + apply, + transaction, + platform_version, + previous_fee_versions, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "update_contract".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } @@ -125,9 +134,18 @@ impl Drive { drive_operations, platform_version, ), + 1 => self.update_contract_element_v1( + contract_element, + contract, + original_contract, + block_info, + transaction, + drive_operations, + platform_version, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "update_contract_element".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } @@ -192,9 +210,19 @@ impl Drive { drive_operations, platform_version, ), + 1 => self.update_contract_add_operations_v1( + contract_element, + contract, + original_contract, + block_info, + estimated_costs_only_with_layer_info, + transaction, + drive_operations, + platform_version, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "update_contract_add_operations".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive/src/drive/contract/update/update_contract/v0/mod.rs b/packages/rs-drive/src/drive/contract/update/update_contract/v0/mod.rs index d95decc3f9..141749a2ff 100644 --- a/packages/rs-drive/src/drive/contract/update/update_contract/v0/mod.rs +++ b/packages/rs-drive/src/drive/contract/update/update_contract/v0/mod.rs @@ -19,7 +19,7 @@ use dpp::serialization::PlatformSerializableWithPlatformVersion; use dpp::fee::default_costs::CachedEpochIndexFeeVersions; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::{HashMap, HashSet}; impl Drive { @@ -198,7 +198,7 @@ impl Drive { } /// operations for updating a contract. - fn update_contract_operations_v0( + pub(in crate::drive::contract::update::update_contract) fn update_contract_operations_v0( &self, contract_element: Element, contract: &DataContract, @@ -300,8 +300,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: element_flags .as_ref() .map(|e| e.len() as u32) @@ -317,7 +317,7 @@ impl Drive { if !index_cache.contains(index_bytes) { self.batch_insert_empty_tree_if_not_exists( PathFixedSizeKeyRef((type_path, index.name.as_bytes())), - false, + TreeType::NormalTree, storage_flags.as_ref().map(|flags| flags.as_ref()), apply_type, transaction, diff --git a/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs b/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs new file mode 100644 index 0000000000..ccd0cde5f1 --- /dev/null +++ b/packages/rs-drive/src/drive/contract/update/update_contract/v1/mod.rs @@ -0,0 +1,253 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::storage_flags::StorageFlags; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::config::v0::DataContractConfigGettersV0; +use dpp::data_contract::DataContract; +use dpp::fee::fee_result::FeeResult; + +use dpp::serialization::PlatformSerializableWithPlatformVersion; + +use crate::error::contract::DataContractError; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Updates a data contract. + /// + /// This function updates a given data contract in the storage. The fee for updating + /// the contract is also calculated and returned. + /// + /// # Arguments + /// + /// * `contract` - A reference to the `DataContract` to be updated. + /// * `block_info` - A `BlockInfo` object containing information about the block where + /// the contract is being updated. + /// * `apply` - A boolean indicating whether the contract update should be applied (`true`) or not (`false`). Passing `false` would only tell the fees but won't interact with the state. + /// * `transaction` - A `TransactionArg` object representing the transaction to be used + /// for updating the contract. + /// + /// # Returns + /// + /// * `Result` - If successful, returns a `FeeResult` representing the fee + /// for updating the contract. If an error occurs during the contract update or fee calculation, + /// returns an `Error`. + /// + /// # Errors + /// + /// This function returns an error if the contract update or fee calculation fails. + #[inline(always)] + pub(super) fn update_contract_v1( + &self, + contract: &DataContract, + block_info: BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + previous_fee_versions: Option<&CachedEpochIndexFeeVersions>, + ) -> Result { + if !apply { + return self.insert_contract( + contract, + block_info, + false, + transaction, + platform_version, + ); + } + + let mut drive_operations: Vec = vec![]; + + let contract_bytes = contract.serialize_to_bytes_with_platform_version(platform_version)?; + + // Since we can update the contract by definition it already has storage flags + let storage_flags = Some(StorageFlags::new_single_epoch( + block_info.epoch.index, + Some(contract.owner_id().to_buffer()), + )); + + let contract_element = Element::Item( + contract_bytes, + StorageFlags::map_to_some_element_flags(storage_flags.as_ref()), + ); + + let original_contract_fetch_info = self + .get_contract_with_fetch_info_and_add_to_operations( + contract.id().to_buffer(), + Some(&block_info.epoch), + true, + transaction, + &mut drive_operations, + platform_version, + )? + .ok_or(Error::Drive(DriveError::CorruptedCodeExecution( + "contract should exist", + )))?; + + if original_contract_fetch_info.contract.config().readonly() { + return Err(Error::Drive(DriveError::UpdatingReadOnlyImmutableContract( + "original contract is readonly", + ))); + } + + self.update_contract_element_v1( + contract_element, + contract, + &original_contract_fetch_info.contract, + &block_info, + transaction, + &mut drive_operations, + platform_version, + )?; + + // Update DataContracts cache with the new contract + let updated_contract_fetch_info = self + .fetch_contract_and_add_operations( + contract.id().to_buffer(), + Some(&block_info.epoch), + transaction, + &mut drive_operations, + platform_version, + )? + .ok_or(Error::Drive(DriveError::CorruptedCodeExecution( + "contract should exist", + )))?; + + self.cache + .data_contracts + .insert(updated_contract_fetch_info, transaction.is_some()); + + Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + previous_fee_versions, + ) + } + + /// Updates a contract. + #[inline(always)] + pub(super) fn update_contract_element_v1( + &self, + contract_element: Element, + contract: &DataContract, + original_contract: &DataContract, + block_info: &BlockInfo, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + None::>; + let batch_operations = self.update_contract_operations_v1( + contract_element, + contract, + original_contract, + block_info, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// Updates a contract. + #[inline(always)] + pub(super) fn update_contract_add_operations_v1( + &self, + contract_element: Element, + contract: &DataContract, + original_contract: &DataContract, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let batch_operations = self.update_contract_operations_v1( + contract_element, + contract, + original_contract, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + drive_operations.extend(batch_operations); + Ok(()) + } + + /// operations for updating a contract. + fn update_contract_operations_v1( + &self, + contract_element: Element, + contract: &DataContract, + original_contract: &DataContract, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = self + .update_contract_operations_v0( + contract_element, + contract, + original_contract, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + for (token_pos, configuration) in contract.tokens() { + let token_id = contract.token_id(*token_pos).ok_or(Error::DataContract( + DataContractError::CorruptedDataContract(format!( + "data contract has a token at position {}, but can not find it", + token_pos + )), + ))?; + + batch_operations.extend(self.create_token_trees_operations( + token_id.to_buffer(), + configuration.start_as_paused(), + true, + &mut None, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + } + + if !contract.groups().is_empty() { + batch_operations.extend(self.add_new_groups_operations( + contract.id(), + contract.groups(), + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + } + + Ok(batch_operations) + } +} diff --git a/packages/rs-drive/src/drive/credit_pools/epochs/operations_factory.rs b/packages/rs-drive/src/drive/credit_pools/epochs/operations_factory.rs index 81248a8e5a..b6ea2661ea 100644 --- a/packages/rs-drive/src/drive/credit_pools/epochs/operations_factory.rs +++ b/packages/rs-drive/src/drive/credit_pools/epochs/operations_factory.rs @@ -20,7 +20,7 @@ use dpp::fee::Credits; use dpp::util::deserializer::ProtocolVersion; use dpp::version::PlatformVersion; use grovedb::batch::QualifiedGroveDbOp; -use grovedb::{Element, TransactionArg}; +use grovedb::{Element, TransactionArg, TreeType}; /// Operations on Epochs pub trait EpochOperations { @@ -288,7 +288,11 @@ impl EpochOperations for Epoch { /// Returns a groveDB op which deletes the epoch proposers tree. fn delete_proposers_tree_operation(&self) -> QualifiedGroveDbOp { - QualifiedGroveDbOp::delete_tree_op(self.get_path_vec(), KEY_PROPOSERS.to_vec(), false) + QualifiedGroveDbOp::delete_tree_op( + self.get_path_vec(), + KEY_PROPOSERS.to_vec(), + TreeType::NormalTree, + ) } /// Adds a groveDB op to the batch which deletes the given epoch proposers from the proposers tree. @@ -421,7 +425,7 @@ mod tests { #[test] fn test_error_if_fee_pools_not_initialized() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); let platform_version = PlatformVersion::first(); @@ -445,10 +449,9 @@ mod tests { #[test] fn test_values_are_set() { - let drive = setup_drive_with_initial_state_structure(None); - let transaction = drive.grove.start_transaction(); - let platform_version = PlatformVersion::first(); + let drive = setup_drive_with_initial_state_structure(Some(platform_version)); + let transaction = drive.grove.start_transaction(); let epoch = Epoch::new(1042).unwrap(); @@ -480,10 +483,9 @@ mod tests { #[test] fn test_values_are_set() { - let drive = setup_drive_with_initial_state_structure(None); - let transaction = drive.grove.start_transaction(); - let platform_version = PlatformVersion::first(); + let drive = setup_drive_with_initial_state_structure(Some(platform_version)); + let transaction = drive.grove.start_transaction(); let epoch = Epoch::new(1042).unwrap(); diff --git a/packages/rs-drive/src/drive/credit_pools/storage_fee_distribution_pool/get_storage_fees_from_distribution_pool/v0/mod.rs b/packages/rs-drive/src/drive/credit_pools/storage_fee_distribution_pool/get_storage_fees_from_distribution_pool/v0/mod.rs index ee90eec06c..bf740821f0 100644 --- a/packages/rs-drive/src/drive/credit_pools/storage_fee_distribution_pool/get_storage_fees_from_distribution_pool/v0/mod.rs +++ b/packages/rs-drive/src/drive/credit_pools/storage_fee_distribution_pool/get_storage_fees_from_distribution_pool/v0/mod.rs @@ -52,7 +52,7 @@ mod tests { #[test] fn test_error_if_epoch_is_not_initiated() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); let platform_version = PlatformVersion::first(); diff --git a/packages/rs-drive/src/drive/credit_pools/unpaid_epoch/get_unpaid_epoch_index/v0/mod.rs b/packages/rs-drive/src/drive/credit_pools/unpaid_epoch/get_unpaid_epoch_index/v0/mod.rs index bcfdaf59b1..def6c7f229 100644 --- a/packages/rs-drive/src/drive/credit_pools/unpaid_epoch/get_unpaid_epoch_index/v0/mod.rs +++ b/packages/rs-drive/src/drive/credit_pools/unpaid_epoch/get_unpaid_epoch_index/v0/mod.rs @@ -57,7 +57,7 @@ mod tests { #[test] fn test_error_if_fee_pools_tree_is_not_initiated() { let platform_version = PlatformVersion::latest(); - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); let result = drive.get_unpaid_epoch_index_v0(Some(&transaction), platform_version); diff --git a/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs index cec20f624a..3f13cfcc6b 100644 --- a/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/delete_document_for_contract_operations/v0/mod.rs @@ -1,6 +1,6 @@ use grovedb::batch::KeyInfoPath; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use dpp::data_contract::document_type::DocumentTypeRef; @@ -83,7 +83,7 @@ impl Drive { &platform_version.drive, )?; DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, query_target: QueryTargetValue( document_type.estimated_size(platform_version)? as u32 ), diff --git a/packages/rs-drive/src/drive/document/delete/internal/add_estimation_costs_for_remove_document_to_primary_storage/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/internal/add_estimation_costs_for_remove_document_to_primary_storage/v0/mod.rs index 2f2863cd4a..ce3ca4d6e5 100644 --- a/packages/rs-drive/src/drive/document/delete/internal/add_estimation_costs_for_remove_document_to_primary_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/internal/add_estimation_costs_for_remove_document_to_primary_storage/v0/mod.rs @@ -1,8 +1,8 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::PotentiallyAtMaxElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllItems; +use grovedb::{EstimatedLayerInformation, TreeType}; use dpp::data_contract::document_type::DocumentTypeRef; @@ -67,7 +67,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(primary_key_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems( DEFAULT_HASH_SIZE_U8, diff --git a/packages/rs-drive/src/drive/document/delete/mod.rs b/packages/rs-drive/src/drive/document/delete/mod.rs index c2da69240b..5a1d2ebbb2 100644 --- a/packages/rs-drive/src/drive/document/delete/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/mod.rs @@ -69,6 +69,7 @@ mod tests { use crate::query::DriveDocumentQuery; use dpp::block::epoch::Epoch; use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::DataContract; use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0; use dpp::document::Document; use dpp::fee::default_costs::KnownCostItem::StorageDiskUsageCreditPerByte; @@ -86,10 +87,11 @@ mod tests { fn test_add_and_remove_family_one_document_no_transaction() { let tmp_dir = TempDir::new().unwrap(); - let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully"); - let platform_version = PlatformVersion::latest(); + let (drive, _) = Drive::open(tmp_dir, None, Some(platform_version)) + .expect("expected to open Drive successfully"); + drive .create_initial_state_structure(None, platform_version) .expect("expected to create root tree successfully"); @@ -99,6 +101,9 @@ mod tests { "tests/supporting_files/contract/family/family-contract-reduced.json", None, None, + None::, + None, + None, ); let document_type = contract @@ -192,7 +197,10 @@ mod tests { &drive, "tests/supporting_files/contract/family/family-contract-reduced.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -333,7 +341,10 @@ mod tests { &drive, "tests/supporting_files/contract/family/family-contract-reduced.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -517,7 +528,10 @@ mod tests { &drive, "tests/supporting_files/contract/family/family-contract-reduced.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -792,7 +806,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let random_owner_id = rand::thread_rng().gen::<[u8; 32]>(); @@ -892,7 +909,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract diff --git a/packages/rs-drive/src/drive/document/delete/remove_document_from_primary_storage/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_document_from_primary_storage/v0/mod.rs index b3ea51c398..07d0b4f564 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_document_from_primary_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_document_from_primary_storage/v0/mod.rs @@ -1,6 +1,6 @@ use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, MaybeTree, TransactionArg, TreeType}; use dpp::data_contract::document_type::DocumentTypeRef; @@ -38,14 +38,14 @@ impl Drive { ) -> Result<(), Error> { let apply_type = if estimated_costs_only_with_layer_info.is_some() { StatelessBatchDelete { - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, estimated_key_size: DEFAULT_HASH_SIZE_U32, estimated_value_size: document_type.estimated_size(platform_version)? as u32, } } else { // we know we are not deleting a subtree StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), } }; self.batch_delete( diff --git a/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs index 6ad033a0f4..a7e531ebb1 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_indices_for_index_level_for_contract_operations/v0/mod.rs @@ -2,7 +2,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::AllSubtrees; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use dpp::data_contract::document_type::IndexLevel; @@ -51,7 +51,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(sub_level_index_count + 1), estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -116,7 +116,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( sub_level_index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( document_top_field_estimated_size as u8, diff --git a/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs index 332e921451..65f48016dd 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v0/mod.rs @@ -2,7 +2,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::AllSubtrees; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use grovedb::EstimatedSumTrees::NoSumTrees; use std::collections::HashMap; @@ -69,7 +69,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(contract_document_type_path.clone()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(sub_level_index_count + 1), estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -119,7 +119,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(index_path.clone()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( document_top_field_estimated_size as u8, diff --git a/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs index 0ee9619ac0..171af54819 100644 --- a/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/delete/remove_reference_for_index_level_for_contract_operations/v0/mod.rs @@ -3,7 +3,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::PotentiallyAtMaxElements; use grovedb::EstimatedLayerSizes::{AllReference, AllSubtrees}; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, MaybeTree, TransactionArg, TreeType}; use dpp::data_contract::document_type::IndexLevelTypeInfo; use dpp::data_contract::document_type::IndexType::{ContestedResourceIndex, NonUniqueIndex}; @@ -64,7 +64,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( key_info_path.clone(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -83,7 +83,7 @@ impl Drive { ), &key_info_path, // we know we are not deleting a tree - Some((false, false)), + Some(MaybeTree::NotTree), estimated_costs_only_with_layer_info, platform_version, )?; @@ -112,7 +112,7 @@ impl Drive { ), &key_info_path, // we know we are not deleting a tree - Some((false, false)), + Some(MaybeTree::NotTree), estimated_costs_only_with_layer_info, platform_version, )?; diff --git a/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_contested_document_to_primary_storage/v0/mod.rs b/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_contested_document_to_primary_storage/v0/mod.rs index 3de9414bc0..2bcaf9ccbc 100644 --- a/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_contested_document_to_primary_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_contested_document_to_primary_storage/v0/mod.rs @@ -11,8 +11,8 @@ use dpp::data_contract::document_type::methods::DocumentTypeV0Methods; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::PotentiallyAtMaxElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllItems; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; use std::collections::HashMap; @@ -77,7 +77,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(primary_key_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems( DEFAULT_HASH_SIZE_U8, diff --git a/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_document_to_primary_storage/v0/mod.rs b/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_document_to_primary_storage/v0/mod.rs index a43d53d1bf..9b5bb29ebd 100644 --- a/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_document_to_primary_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/estimation_costs/add_estimation_costs_for_add_document_to_primary_storage/v0/mod.rs @@ -15,9 +15,9 @@ use dpp::document::DocumentV0Getters; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees, Mix}; use grovedb::EstimatedSumTrees::NoSumTrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::util::type_constants::{ DEFAULT_FLOAT_SIZE, DEFAULT_FLOAT_SIZE_U8, DEFAULT_HASH_SIZE_U8, @@ -84,7 +84,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(primary_key_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -108,7 +108,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(document_id_in_primary_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(AVERAGE_NUMBER_OF_UPDATES as u32), estimated_layer_sizes: Mix { subtrees_size: None, @@ -137,7 +137,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(primary_key_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems( DEFAULT_HASH_SIZE_U8, diff --git a/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/mod.rs b/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/mod.rs index 4d8a852d84..d31bad5cf5 100644 --- a/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/mod.rs +++ b/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/mod.rs @@ -1,6 +1,6 @@ mod v0; -use crate::util::grove_operations::{BatchDeleteUpTreeApplyType, IsSubTree, IsSumSubTree}; +use crate::util::grove_operations::BatchDeleteUpTreeApplyType; use crate::drive::Drive; @@ -10,7 +10,7 @@ use crate::error::drive::DriveError; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, EstimatedLayerSizes}; +use grovedb::{EstimatedLayerInformation, EstimatedLayerSizes, MaybeTree}; use std::collections::HashMap; @@ -39,7 +39,7 @@ impl Drive { pub(crate) fn stateless_delete_of_non_tree_for_costs( element_estimated_sizes: EstimatedLayerSizes, key_info_path: &KeyInfoPath, - is_known_to_be_subtree_with_sum: Option<(IsSubTree, IsSumSubTree)>, + is_known_to_be_subtree_with_sum: Option, estimated_costs_only_with_layer_info: &mut Option< HashMap, >, diff --git a/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/v0/mod.rs b/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/v0/mod.rs index cf2b79c56d..bcd8ac056f 100644 --- a/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/estimation_costs/stateless_delete_of_non_tree_for_costs/v0/mod.rs @@ -1,6 +1,6 @@ use crate::drive::constants::CONTRACT_DOCUMENTS_PATH_HEIGHT; -use crate::util::grove_operations::{BatchDeleteUpTreeApplyType, IsSubTree, IsSumSubTree}; +use crate::util::grove_operations::BatchDeleteUpTreeApplyType; use crate::drive::Drive; use crate::error::fee::FeeError; @@ -8,7 +8,7 @@ use crate::error::Error; use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, EstimatedLayerSizes}; +use grovedb::{EstimatedLayerInformation, EstimatedLayerSizes, MaybeTree}; use intmap::IntMap; use itertools::Itertools; use std::collections::HashMap; @@ -41,7 +41,7 @@ impl Drive { pub(super) fn stateless_delete_of_non_tree_for_costs_v0( element_estimated_sizes: EstimatedLayerSizes, key_info_path: &KeyInfoPath, - is_known_to_be_subtree_with_sum: Option<(IsSubTree, IsSumSubTree)>, + is_known_to_be_subtree_with_sum: Option, estimated_costs_only_with_layer_info: &mut Option< HashMap, >, diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/mod.rs index 0af032f910..8ffb92bdcc 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/mod.rs @@ -13,7 +13,7 @@ use dpp::validation::SimpleConsensusValidationResult; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionAction; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/v0/mod.rs index 5f9c96d1ab..33a1fdcc9d 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_create_transition_action_uniqueness/v0/mod.rs @@ -19,8 +19,8 @@ use dpp::document::property_names::{ }; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs index a4e3bc9d05..75baec39ad 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/mod.rs @@ -13,7 +13,7 @@ use dpp::validation::SimpleConsensusValidationResult; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionAction; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs index a9673724cf..05bee3b7e1 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_purchase_transition_action_uniqueness/v0/mod.rs @@ -14,8 +14,8 @@ use dpp::validation::SimpleConsensusValidationResult; use dpp::document::DocumentV0Getters; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/mod.rs index 4b16308fd4..05deb0d487 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/mod.rs @@ -13,7 +13,7 @@ use dpp::validation::SimpleConsensusValidationResult; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::DocumentReplaceTransitionAction; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/v0/mod.rs index 8930e78be5..5dbea70762 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_replace_transition_action_uniqueness/v0/mod.rs @@ -13,8 +13,8 @@ use dpp::validation::SimpleConsensusValidationResult; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/mod.rs index b72f8d55ae..16c272b541 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/mod.rs @@ -13,7 +13,7 @@ use dpp::validation::SimpleConsensusValidationResult; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::DocumentTransferTransitionAction; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/v0/mod.rs index a4a2551716..638fcdd852 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_transfer_transition_action_uniqueness/v0/mod.rs @@ -14,8 +14,8 @@ use dpp::validation::SimpleConsensusValidationResult; use dpp::document::DocumentV0Getters; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs index 6d412a95ab..f60019f474 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/mod.rs @@ -13,7 +13,7 @@ use dpp::validation::SimpleConsensusValidationResult; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::DocumentUpdatePriceTransitionAction; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs index 21b3d94564..feb615a504 100644 --- a/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/index_uniqueness/validate_document_update_price_transition_action_uniqueness/v0/mod.rs @@ -14,8 +14,8 @@ use dpp::validation::SimpleConsensusValidationResult; use dpp::document::DocumentV0Getters; use grovedb::TransactionArg; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; impl Drive { diff --git a/packages/rs-drive/src/drive/document/insert/add_document_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_document_for_contract_operations/v0/mod.rs index 1faf95a1dc..f072477da8 100644 --- a/packages/rs-drive/src/drive/document/insert/add_document_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_document_for_contract_operations/v0/mod.rs @@ -12,7 +12,7 @@ use dpp::data_contract::document_type::methods::DocumentTypeV0Methods; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -41,7 +41,7 @@ impl Drive { StatefulDirectQuery } else { StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, query_target: QueryTargetValue( document_and_contract_info .document_type diff --git a/packages/rs-drive/src/drive/document/insert/add_document_to_primary_storage/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_document_to_primary_storage/v0/mod.rs index f0ecde6e3e..ea1ae0f2a7 100644 --- a/packages/rs-drive/src/drive/document/insert/add_document_to_primary_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_document_to_primary_storage/v0/mod.rs @@ -5,7 +5,7 @@ use grovedb::batch::key_info::KeyInfo::KnownKey; use grovedb::batch::KeyInfoPath; use grovedb::reference_path::ReferencePathType::SiblingReference; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; use std::option::Option::None; @@ -125,8 +125,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -135,7 +135,7 @@ impl Drive { // we first insert an empty tree if the document is new self.batch_insert_empty_tree_if_not_exists( path_key_info, - false, + TreeType::NormalTree, storage_flags, apply_type, transaction, @@ -425,7 +425,7 @@ impl Drive { BatchInsertApplyType::StatefulBatchInsert } else { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, target: QueryTargetValue(document_type.estimated_size(platform_version)? as u32), } }; diff --git a/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs index 2725cc80b1..0bfcf82e67 100644 --- a/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_indices_for_index_level_for_contract_operations/v0/mod.rs @@ -14,7 +14,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::AllSubtrees; use grovedb::EstimatedSumTrees::NoSumTrees; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -62,7 +62,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(sub_level_index_count + 1), estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -77,8 +77,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -109,7 +109,7 @@ impl Drive { // here we are inserting an empty tree that will have a subtree of all other index properties self.batch_insert_empty_tree_if_not_exists( path_key_info.clone(), - false, + TreeType::NormalTree, *storage_flags, apply_type, transaction, @@ -136,7 +136,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( sub_level_index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( document_top_field_estimated_size as u8, @@ -157,7 +157,7 @@ impl Drive { // here we are inserting an empty tree that will have a subtree of all other index properties self.batch_insert_empty_tree_if_not_exists( path_key_info.clone(), - false, + TreeType::NormalTree, *storage_flags, apply_type, transaction, diff --git a/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs index c21146a183..4ca3e7662d 100644 --- a/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v0/mod.rs @@ -20,7 +20,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::AllSubtrees; use grovedb::EstimatedSumTrees::NoSumTrees; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -70,7 +70,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(contract_document_type_path.clone()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(sub_level_index_count + 1), estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -85,8 +85,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -120,7 +120,7 @@ impl Drive { // here we are inserting an empty tree that will have a subtree of all other index properties self.batch_insert_empty_tree_if_not_exists( path_key_info.clone(), - false, + TreeType::NormalTree, storage_flags, apply_type, transaction, @@ -146,7 +146,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(index_path.clone()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( document_top_field_estimated_size as u8, diff --git a/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs index 00d3f872cd..c3744cbcdc 100644 --- a/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/add_reference_for_index_level_for_contract_operations/v0/mod.rs @@ -23,7 +23,7 @@ use grovedb::batch::key_info::KeyInfo; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::PotentiallyAtMaxElements; use grovedb::EstimatedLayerSizes::AllReference; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -61,8 +61,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -75,7 +75,7 @@ impl Drive { // a contested resource index self.batch_insert_empty_tree_if_not_exists( path_key_info, - false, + TreeType::NormalTree, *storage_flags, apply_type, transaction, @@ -94,7 +94,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllReference( DEFAULT_HASH_SIZE_U8, @@ -194,7 +194,7 @@ impl Drive { BatchInsertApplyType::StatefulBatchInsert } else { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, target: QueryTargetValue( document_reference_size(document_and_contract_info.document_type) + storage_flags diff --git a/packages/rs-drive/src/drive/document/insert/mod.rs b/packages/rs-drive/src/drive/document/insert/mod.rs index d439a05e99..9b430e8a85 100644 --- a/packages/rs-drive/src/drive/document/insert/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/mod.rs @@ -51,11 +51,11 @@ mod tests { use once_cell::sync::Lazy; use std::collections::BTreeMap; - use dpp::block::epoch::Epoch; - use dpp::data_contract::accessors::v0::DataContractV0Getters; - use crate::util::object_size_info::DocumentInfo::DocumentRefInfo; use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::epoch::Epoch; + use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::DataContract; use dpp::fee::default_costs::KnownCostItem::StorageDiskUsageCreditPerByte; use dpp::fee::default_costs::{CachedEpochIndexFeeVersions, EpochCosts}; use dpp::fee::fee_result::FeeResult; @@ -165,7 +165,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -261,7 +264,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -399,7 +405,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -439,7 +448,6 @@ mod tests { None, ) .expect("expected to insert a document successfully"); - assert_eq!(fee_result, expected_fee_result); } @@ -455,7 +463,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", None, + None, + None::, Some(&db_transaction), + None, ); let random_owner_id = random::<[u8; 32]>(); @@ -531,7 +542,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json", None, + None, + None::, Some(&db_transaction), + None, ); let random_owner_id = random::<[u8; 32]>(); @@ -624,7 +638,10 @@ mod tests { &drive, "tests/supporting_files/contract/dpns/dpns-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let random_owner_id = rand::thread_rng().gen::<[u8; 32]>(); diff --git a/packages/rs-drive/src/drive/document/insert_contested/add_contested_document_to_primary_storage/v0/mod.rs b/packages/rs-drive/src/drive/document/insert_contested/add_contested_document_to_primary_storage/v0/mod.rs index 5df447b5ef..5a18464be3 100644 --- a/packages/rs-drive/src/drive/document/insert_contested/add_contested_document_to_primary_storage/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert_contested/add_contested_document_to_primary_storage/v0/mod.rs @@ -1,7 +1,7 @@ use grovedb::batch::key_info::KeyInfo; use grovedb::batch::KeyInfoPath; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; @@ -203,7 +203,7 @@ impl Drive { BatchInsertApplyType::StatefulBatchInsert } else { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, target: QueryTargetValue(document_type.estimated_size(platform_version)? as u32), } }; diff --git a/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_contract_operations/v0/mod.rs index 1881419fdd..52297150a0 100644 --- a/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_contract_operations/v0/mod.rs @@ -23,7 +23,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::AllSubtrees; use grovedb::EstimatedSumTrees::NoSumTrees; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -74,8 +74,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -123,7 +123,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( document_top_field_estimated_size as u8, @@ -153,7 +153,7 @@ impl Drive { document_top_field .clone() .add_path_info(index_path_info.clone()), - false, + TreeType::NormalTree, storage_flags, apply_type, transaction, @@ -187,7 +187,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(16), // very seldom would more than 16 people want the resource estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -200,7 +200,7 @@ impl Drive { self.batch_insert_empty_tree_if_not_exists( DriveKeyInfo::Key(owner_id.to_vec()).add_path_info(index_path_info.clone()), - false, + TreeType::NormalTree, storage_flags, apply_type, transaction, @@ -212,7 +212,7 @@ impl Drive { let inserted_abstain = self.batch_insert_empty_tree_if_not_exists( DriveKeyInfo::Key(RESOURCE_ABSTAIN_VOTE_TREE_KEY_U8_32.to_vec()) .add_path_info(index_path_info.clone()), - false, + TreeType::NormalTree, storage_flags, apply_type, transaction, @@ -224,7 +224,7 @@ impl Drive { let inserted_lock = self.batch_insert_empty_tree_if_not_exists( DriveKeyInfo::Key(RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.to_vec()) .add_path_info(index_path_info.clone()), - false, + TreeType::NormalTree, storage_flags, apply_type, transaction, diff --git a/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_index_level_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_index_level_for_contract_operations/v0/mod.rs index a989dd3997..a1ecffebb3 100644 --- a/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_index_level_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert_contested/add_contested_indices_for_index_level_for_contract_operations/v0/mod.rs @@ -60,7 +60,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(sub_level_index_count + 1), estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, @@ -76,7 +76,7 @@ impl Drive { } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { in_tree_using_sums: false, - is_sum_tree: false, + tree_type: TreeType::NormalTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -134,7 +134,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( sub_level_index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( document_top_field_estimated_size as u8, diff --git a/packages/rs-drive/src/drive/document/insert_contested/add_contested_reference_and_vote_subtree_to_document_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert_contested/add_contested_reference_and_vote_subtree_to_document_operations/v0/mod.rs index 3bc068d4f1..cd4fa6ecd1 100644 --- a/packages/rs-drive/src/drive/document/insert_contested/add_contested_reference_and_vote_subtree_to_document_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert_contested/add_contested_reference_and_vote_subtree_to_document_operations/v0/mod.rs @@ -21,7 +21,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::{AllItems, Mix}; use grovedb::EstimatedSumTrees::AllSumTrees; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -53,7 +53,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(2), estimated_layer_sizes: Mix { // The votes don't have storage flags @@ -144,7 +144,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( votes_path_key_info.clone().convert_to_key_info_path()?, EstimatedLayerInformation { - is_sum_tree: true, + tree_type: TreeType::SumTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, U8_SIZE_U32, None), }, @@ -155,8 +155,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: true, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::SumTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -166,7 +166,7 @@ impl Drive { // here we are the tree that will contain the voting tree let inserted = self.batch_insert_empty_tree_if_not_exists( votes_path_key_info, - true, + TreeType::SumTree, storage_flags, apply_type, transaction, diff --git a/packages/rs-drive/src/drive/document/insert_contested/add_contested_vote_subtrees_for_non_identities_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/insert_contested/add_contested_vote_subtrees_for_non_identities_operations/v0/mod.rs index bb036014bd..c6d8faedcb 100644 --- a/packages/rs-drive/src/drive/document/insert_contested/add_contested_vote_subtrees_for_non_identities_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/insert_contested/add_contested_vote_subtrees_for_non_identities_operations/v0/mod.rs @@ -12,7 +12,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; use grovedb::EstimatedLayerSizes::{AllItems, Mix}; use grovedb::EstimatedSumTrees::AllSumTrees; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -43,7 +43,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( index_path_info.clone().convert_to_key_info_path(), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(1), estimated_layer_sizes: Mix { // The votes don't have storage flags @@ -71,7 +71,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( votes_path_key_info.clone().convert_to_key_info_path()?, EstimatedLayerInformation { - is_sum_tree: true, + tree_type: TreeType::SumTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, U8_SIZE_U32, None), }, @@ -82,8 +82,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: true, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::SumTree, flags_len: storage_flags .map(|s| s.serialized_size()) .unwrap_or_default(), @@ -93,7 +93,7 @@ impl Drive { // here we are the tree that will contain the voting tree let inserted = self.batch_insert_empty_tree_if_not_exists( votes_path_key_info.clone(), - true, + TreeType::SumTree, storage_flags, apply_type, transaction, diff --git a/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs b/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs index 0c92a15651..5a6a14e759 100644 --- a/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs @@ -34,7 +34,7 @@ use dpp::version::PlatformVersion; use grovedb::batch::key_info::KeyInfo; use grovedb::batch::key_info::KeyInfo::KnownKey; use grovedb::batch::KeyInfoPath; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, MaybeTree, TransactionArg, TreeType}; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; @@ -227,7 +227,7 @@ impl Drive { index_path.clone(), document_top_field.as_slice(), )), - false, + TreeType::NormalTree, storage_flags, BatchInsertTreeApplyType::StatefulBatchInsertTree, transaction, @@ -300,7 +300,7 @@ impl Drive { index_path.clone(), index_property.name.as_bytes(), )), - false, + TreeType::NormalTree, storage_flags, BatchInsertTreeApplyType::StatefulBatchInsertTree, transaction, @@ -332,7 +332,7 @@ impl Drive { index_path.clone(), document_index_field.as_slice(), )), - false, + TreeType::NormalTree, storage_flags, BatchInsertTreeApplyType::StatefulBatchInsertTree, transaction, @@ -380,7 +380,7 @@ impl Drive { document.id().as_slice(), Some(CONTRACT_DOCUMENTS_PATH_HEIGHT), BatchDeleteUpTreeApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, previous_batch_operations, @@ -394,7 +394,7 @@ impl Drive { &[0], Some(CONTRACT_DOCUMENTS_PATH_HEIGHT), BatchDeleteUpTreeApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, previous_batch_operations, @@ -409,7 +409,7 @@ impl Drive { // here we are inserting an empty tree that will have a subtree of all other index properties self.batch_insert_empty_tree_if_not_exists( PathKeyInfo::PathKeyRef::<0>((index_path.clone(), &[0])), - false, + TreeType::NormalTree, storage_flags, BatchInsertTreeApplyType::StatefulBatchInsertTree, transaction, diff --git a/packages/rs-drive/src/drive/document/update/mod.rs b/packages/rs-drive/src/drive/document/update/mod.rs index fccb43e3e8..478921f994 100644 --- a/packages/rs-drive/src/drive/document/update/mod.rs +++ b/packages/rs-drive/src/drive/document/update/mod.rs @@ -684,7 +684,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -773,7 +776,10 @@ mod tests { &drive, "tests/supporting_files/contract/dashpay/dashpay-contract-with-profile-history.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -846,7 +852,7 @@ mod tests { let platform_version = PlatformVersion::latest(); - let drive: Drive = setup_drive(Some(config)); + let drive: Drive = setup_drive(Some(config), None); let transaction = if using_transaction { Some(drive.grove.start_transaction()) @@ -865,7 +871,15 @@ mod tests { }; // setup code - let contract = setup_contract(&drive, path, None, transaction.as_ref()); + let contract = setup_contract( + &drive, + path, + None, + None, + None::, + transaction.as_ref(), + None, + ); let id = Identifier::from([1u8; 32]); let owner_id = Identifier::from([2u8; 32]); @@ -1141,7 +1155,7 @@ mod tests { let platform_version = PlatformVersion::latest(); - let drive: Drive = setup_drive(Some(config)); + let drive: Drive = setup_drive(Some(config), None); let transaction = if using_transaction { Some(drive.grove.start_transaction()) @@ -1160,7 +1174,15 @@ mod tests { }; // setup code - let contract = setup_contract(&drive, path, None, transaction.as_ref()); + let contract = setup_contract( + &drive, + path, + None, + None, + None::, + transaction.as_ref(), + None, + ); let id = Identifier::from([1u8; 32]); let owner_id = Identifier::from([2u8; 32]); @@ -1340,7 +1362,7 @@ mod tests { let platform_version = PlatformVersion::latest(); - let drive: Drive = setup_drive(Some(config)); + let drive: Drive = setup_drive(Some(config), None); let transaction = if using_transaction { Some(drive.grove.start_transaction()) @@ -1359,7 +1381,15 @@ mod tests { }; // setup code - let contract = setup_contract(&drive, path, None, transaction.as_ref()); + let contract = setup_contract( + &drive, + path, + None, + None, + None::, + transaction.as_ref(), + None, + ); let id = Identifier::from([1u8; 32]); let owner_id = Identifier::from([2u8; 32]); @@ -1675,7 +1705,7 @@ mod tests { let platform_version = PlatformVersion::latest(); - let drive: Drive = setup_drive(Some(config)); + let drive: Drive = setup_drive(Some(config), None); let transaction = if using_transaction { Some(drive.grove.start_transaction()) @@ -1694,7 +1724,15 @@ mod tests { }; // setup code - let contract = setup_contract(&drive, path, None, transaction.as_ref()); + let contract = setup_contract( + &drive, + path, + None, + None, + None::, + transaction.as_ref(), + None, + ); let person_0_original = Person { id: Identifier::from([0u8; 32]), diff --git a/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/mod.rs b/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/mod.rs new file mode 100644 index 0000000000..efef30d2df --- /dev/null +++ b/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/mod.rs @@ -0,0 +1,79 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::data_contract::GroupContractPosition; +use dpp::version::drive_versions::DriveVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerInformation; +use std::collections::HashMap; + +impl Drive { + /// Adds estimation costs for adding a group action based on the specified contract and version. + /// + /// This function selects the appropriate version of cost estimation for adding a group action, depending on the + /// `drive_version` provided. It then delegates the cost estimation to the relevant method for that version. + /// + /// Currently, it supports version `0` which uses the `add_estimation_costs_for_add_group_action_v0` method to estimate + /// the computational costs associated with adding a group action. If an unsupported version is passed in the `drive_version`, + /// the function will return an error indicating a version mismatch. + /// + /// # Parameters + /// + /// - `contract_id`: The unique identifier of the contract for which the group action is being added. + /// This is used to form paths and calculate relevant costs. + /// - `group_contract_position`: The position of the group contract within the system, influencing the paths used for cost estimation. + /// - `action_id`: An optional identifier for the specific action being added. If provided, the estimation for this action and its signers is included. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to a `HashMap` where the estimated costs for updating + /// the group action and its associated data will be stored. The keys in the map represent paths to the trees, + /// and the values represent the estimated computational costs for those trees. + /// - `drive_version`: The version of the drive being used. It determines which method to use for cost estimation. + /// This is a versioned API, so different versions may have different cost estimation methods. + /// + /// # Return Value + /// + /// - Returns `Ok(())` if the version of the `drive_version` matches the supported versions and the estimation is successfully added. + /// - Returns an error (`Error::Drive(DriveError::UnknownVersionMismatch)`) if the version is not supported. + /// + /// # Logic Breakdown + /// + /// - **Version Selection**: The function first checks the version provided in `drive_version`. If the version is `0`, + /// it uses the `add_estimation_costs_for_add_group_action_v0` method for cost estimation. + /// - **Version Mismatch**: If the version does not match the supported versions, an error is returned with details + /// about the expected versions and the received version. + /// + /// # Errors + /// + /// - `Error::Drive(DriveError::UnknownVersionMismatch)` will be returned if the `drive_version` does not match the + /// known versions supported for this method (currently only version `0`). + pub(crate) fn add_estimation_costs_for_add_group_action( + contract_id: [u8; 32], + group_contract_position: GroupContractPosition, + action_id: Option<[u8; 32]>, + estimated_costs_only_with_layer_info: &mut HashMap, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .methods + .group + .cost_estimation + .for_add_group_action + { + 0 => { + Self::add_estimation_costs_for_add_group_action_v0( + contract_id, + group_contract_position, + action_id, + estimated_costs_only_with_layer_info, + ); + Ok(()) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_estimation_costs_for_add_group_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs b/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs new file mode 100644 index 0000000000..5923c6a14d --- /dev/null +++ b/packages/rs-drive/src/drive/group/estimated_costs/for_add_group_action/v0/mod.rs @@ -0,0 +1,173 @@ +use crate::drive::Drive; + +use crate::drive::group::paths::{ + group_action_path, group_action_root_path, group_action_signers_path, group_contract_path, + group_path, group_root_path, +}; +use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; +use dpp::data_contract::GroupContractPosition; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::EstimatedLevel; +use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees, Mix}; +use grovedb::EstimatedSumTrees::{AllSumTrees, NoSumTrees, SomeSumTrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; +use std::collections::HashMap; + +impl Drive { + /// Adds estimated costs for the layer information of group action 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. + /// - `group_contract_position`: The position of the group contract in the system, used to further specify paths. + /// - `action_id`: An optional identifier for the specific action being added. If provided, additional paths for + /// the action and its associated signers will be included. + /// - `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(super) fn add_estimation_costs_for_add_group_action_v0( + contract_id: [u8; 32], + group_contract_position: GroupContractPosition, + action_id: Option<[u8; 32]>, + 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), + }, + ); + + 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), + }, + ); + + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(group_action_root_path( + contract_id.as_slice(), + &group_contract_position.to_be_bytes(), + )), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), + }, + ); + + if let Some(action_id) = action_id { + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(group_action_path( + contract_id.as_slice(), + &group_contract_position.to_be_bytes(), + action_id.as_slice(), + )), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(1, false), + estimated_layer_sizes: Mix { + subtrees_size: Some((1, AllSumTrees, None, 1)), + items_size: Some((1, 8, Some(36), 1)), + references_size: None, + }, + }, + ); + + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(group_action_signers_path( + contract_id.as_slice(), + &group_contract_position.to_be_bytes(), + action_id.as_slice(), + )), + EstimatedLayerInformation { + tree_type: TreeType::SumTree, + estimated_layer_count: EstimatedLevel(1, false), + estimated_layer_sizes: AllItems(8, 1, 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 new file mode 100644 index 0000000000..ef47daecce --- /dev/null +++ b/packages/rs-drive/src/drive/group/estimated_costs/mod.rs @@ -0,0 +1 @@ +mod for_add_group_action; diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/mod.rs new file mode 100644 index 0000000000..1aa5d30a10 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/mod.rs @@ -0,0 +1,118 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::GroupContractPosition; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +mod v0; + +impl Drive { + /// Fetches if an identity has already signed in an action + pub fn fetch_action_id_has_signer( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_has_signer + { + 0 => self.fetch_action_id_has_signer_v0( + contract_id, + group_contract_position, + action_id, + signer_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_has_signer".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + /// Fetches if an identity has already signed in an action with costs + + pub fn fetch_action_id_has_signer_with_costs( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_id: Identifier, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(bool, FeeResult), Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_has_signer + { + 0 => self.fetch_action_id_has_signer_with_costs_v0( + contract_id, + group_contract_position, + action_id, + signer_id, + block_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_has_signer_with_costs".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + pub(crate) fn fetch_action_id_has_signer_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_id: Identifier, + estimate_costs_only: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_has_signer + { + 0 => self.fetch_action_id_has_signer_and_add_operations_v0( + contract_id, + group_contract_position, + action_id, + signer_id, + estimate_costs_only, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_has_signer_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/v0/mod.rs new file mode 100644 index 0000000000..de19a8cc86 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_has_signer/v0/mod.rs @@ -0,0 +1,165 @@ +use crate::drive::group::paths::group_action_signers_path; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::GroupContractPosition; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::{TransactionArg, TreeType}; + +impl Drive { + /// v0 implementation of fetching the signers' power for a given action ID within a group contract. + /// + /// This function retrieves the signers' power associated with a specific action ID in a group contract. + /// It constructs the appropriate GroveDB path, fetches the relevant data, deserializes it, and + /// calculates any applicable fees based on the provided epoch. + /// + /// # Parameters + /// * `contract_id` - The identifier of the contract. + /// * `group_contract_position` - The position of the group contract within the data contract. + /// * `action_id` - The identifier of the action whose signers' power is to be fetched. + /// * `apply` - A boolean flag indicating whether to apply certain operations during the fetch. + /// * `transaction` - The GroveDB transaction argument for executing the fetch operation. + /// * `platform_version` - The current platform version, used to ensure compatibility. + /// + /// # Returns + /// * `Ok(Some(Arc))` if the signers' power is successfully fetched. + /// * `Ok(None)` if the signers' power does not exist. + /// * `Err(Error)` if an error occurs during the fetch operation. + /// + /// # Errors + /// * `Error::Drive(DriveError::CorruptedContractPath)` if the fetched path does not refer to a valid sum item. + /// * `Error::Drive(DriveError::CorruptedCodeExecution)` if the element type is unexpected. + /// * `Error::GroveDB` for any underlying GroveDB errors. + pub(super) fn fetch_action_id_has_signer_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_signers_path( + contract_id.as_slice(), + &group_contract_position_bytes, + action_id.as_slice(), + ); + + let value = self.grove_has_raw( + (&path).into(), + signer_id.as_slice(), + DirectQueryType::StatefulDirectQuery, + transaction, + &mut vec![], + &platform_version.drive, + )?; + + Ok(value) + } + + /// Fetches the Identity's balance from the backing store + /// Passing apply as false get the estimated cost instead + pub(super) fn fetch_action_id_has_signer_with_costs_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_id: Identifier, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(bool, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_action_id_has_signer_and_add_operations_v0( + contract_id, + group_contract_position, + action_id, + signer_id, + false, + transaction, + &mut drive_operations, + platform_version, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + Ok((value, fees)) + } + + /// v0 implementation of fetching the signers' power for a given action ID within a group contract and adding related operations. + /// + /// This function not only fetches the signers' power but also appends necessary low-level drive operations based on the provided epoch. + /// It ensures that fees are calculated and added to the `drive_operations` vector when applicable. + /// + /// # Parameters + /// * `contract_id` - The identifier of the contract. + /// * `group_contract_position` - The position of the group contract within the data contract. + /// * `action_id` - The identifier of the action whose signers' power is to be fetched. + /// * `epoch` - An optional reference to an `Epoch` object. If provided, fees will be calculated based on the epoch. + /// * `transaction` - The GroveDB transaction argument for executing the fetch operation. + /// * `drive_operations` - A mutable reference to a vector where low-level drive operations and fees will be appended. + /// * `platform_version` - The current platform version, used to ensure compatibility. + /// + /// # Returns + /// * `Ok(Some(Arc))` if the signers' power is successfully fetched. + /// * `Ok(None)` if the signers' power does not exist. + /// * `Err(Error)` if an error occurs during the fetch operation. + /// + /// # Errors + /// * `Error::Drive(DriveError::CorruptedContractPath)` if the fetched path does not refer to a valid sum item. + /// * `Error::Drive(DriveError::CorruptedCodeExecution)` if the element type is unexpected. + /// * `Error::Drive(DriveError::NotSupportedPrivate)` if stateful batch insertions are attempted. + /// * `Error::GroveDB` for any underlying GroveDB errors. + pub(super) fn fetch_action_id_has_signer_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + signer_id: Identifier, + estimate_costs_only: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_signers_path( + contract_id.as_slice(), + &group_contract_position_bytes, + action_id.as_slice(), + ); + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimate_costs_only { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::SumTree, + query_target: QueryTargetValue(8), + } + } else { + DirectQueryType::StatefulDirectQuery + }; + + let value = self.grove_has_raw( + (&path).into(), + signer_id.as_slice(), + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )?; + + Ok(value) + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs new file mode 100644 index 0000000000..99c38f711e --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/mod.rs @@ -0,0 +1,121 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Fetches the `GroupAction` for the given action ID and group contract position. + /// + /// This function queries the GroveDB to fetch the `GroupAction` associated with a specific + /// group contract position and action ID. The method selects the appropriate version of + /// `fetch_action_id_info` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn fetch_action_id_info( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_info + { + 0 => self.fetch_action_id_info_v0( + contract_id, + group_contract_position, + action_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_info".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the `GroupAction` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `fetch_action_id_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose `GroupAction` is being fetched. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing + /// layer information used for cost estimation. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(GroupAction)`: The `GroupAction` for the specified action ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn fetch_action_id_info_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_info + { + 0 => self.fetch_action_id_info_and_add_operations_v0( + contract_id, + group_contract_position, + action_id, + estimated_costs_only_with_layer_info, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_signers_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs new file mode 100644 index 0000000000..723e7312cd --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info/v0/mod.rs @@ -0,0 +1,91 @@ +use std::collections::HashMap; + +use crate::drive::group::paths::{group_action_path, ACTION_INFO_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformDeserializable; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; + +impl Drive { + pub(super) fn fetch_action_id_info_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_path( + contract_id.as_ref(), + &group_contract_position_bytes, + action_id.as_ref(), + ); + + let value = self.grove_get_raw_item( + (&path).into(), + ACTION_INFO_KEY, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut vec![], + &platform_version.drive, + )?; + + let group_action = GroupAction::deserialize_from_bytes(&value)?; + + Ok(group_action) + } + + pub(super) fn fetch_action_id_info_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_path( + contract_id.as_ref(), + &group_contract_position_bytes, + action_id.as_ref(), + ); + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let value = self.grove_get_raw_item( + (&path).into(), + ACTION_INFO_KEY, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )?; + + let group_action = GroupAction::deserialize_from_bytes(&value)?; + + Ok(group_action) + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/mod.rs new file mode 100644 index 0000000000..515c1d0e4a --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/mod.rs @@ -0,0 +1,120 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Fetches the serialized `GroupAction` for the given action ID and group contract position. + /// + /// This function retrieves the serialized bytes of the `GroupAction` associated with a specific + /// action ID and group contract position from the GroveDB. The method selects the appropriate version + /// of `fetch_action_id_info_keep_serialized` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose serialized `GroupAction` is being fetched. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Vec)`: The serialized `GroupAction` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn fetch_action_id_info_keep_serialized( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_info_keep_serialized + { + 0 => self.fetch_action_id_info_keep_serialized_v0( + contract_id, + group_contract_position, + action_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_info_keep_serialized".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the serialized `GroupAction` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `fetch_action_id_info_keep_serialized`, but also adds operations to the drive for state changes + /// or queries. Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `action_id`: The identifier of the action whose serialized `GroupAction` is being fetched. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing + /// layer information used for cost estimation. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Vec)`: The serialized `GroupAction` for the specified action ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn fetch_action_id_info_keep_serialized_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_info_keep_serialized + { + 0 => self.fetch_action_id_info_keep_serialized_and_add_operations_v0( + contract_id, + group_contract_position, + action_id, + estimated_costs_only_with_layer_info, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_signers_keep_serialized_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/v0/mod.rs new file mode 100644 index 0000000000..504ade4fa5 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_info_keep_serialized/v0/mod.rs @@ -0,0 +1,132 @@ +use std::collections::HashMap; + +use crate::drive::group::paths::{group_action_path, ACTION_INFO_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; + +impl Drive { + /// v0 implementation of fetching the signers' power for a given action ID within a group contract. + /// + /// This function retrieves the signers' power associated with a specific action ID in a group contract. + /// It constructs the appropriate GroveDB path, fetches the relevant data, deserializes it, and + /// calculates any applicable fees based on the provided epoch. + /// + /// # Parameters + /// * `contract_id` - The identifier of the contract. + /// * `group_contract_position` - The position of the group contract within the data contract. + /// * `action_id` - The identifier of the action whose signers' power is to be fetched. + /// * `apply` - A boolean flag indicating whether to apply certain operations during the fetch. + /// * `transaction` - The GroveDB transaction argument for executing the fetch operation. + /// * `platform_version` - The current platform version, used to ensure compatibility. + /// + /// # Returns + /// * `Ok(Some(Arc))` if the signers' power is successfully fetched. + /// * `Ok(None)` if the signers' power does not exist. + /// * `Err(Error)` if an error occurs during the fetch operation. + /// + /// # Errors + /// * `Error::Drive(DriveError::CorruptedContractPath)` if the fetched path does not refer to a valid sum item. + /// * `Error::Drive(DriveError::CorruptedCodeExecution)` if the element type is unexpected. + /// * `Error::GroveDB` for any underlying GroveDB errors. + pub(super) fn fetch_action_id_info_keep_serialized_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_path( + contract_id.as_ref(), + &group_contract_position_bytes, + action_id.as_ref(), + ); + + let value = self.grove_get_raw_item( + (&path).into(), + ACTION_INFO_KEY, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut vec![], + &platform_version.drive, + )?; + + Ok(value) + } + + /// v0 implementation of fetching the signers' power for a given action ID within a group contract and adding related operations. + /// + /// This function not only fetches the signers' power but also appends necessary low-level drive operations based on the provided epoch. + /// It ensures that fees are calculated and added to the `drive_operations` vector when applicable. + /// + /// # Parameters + /// * `contract_id` - The identifier of the contract. + /// * `group_contract_position` - The position of the group contract within the data contract. + /// * `action_id` - The identifier of the action whose signers' power is to be fetched. + /// * `epoch` - An optional reference to an `Epoch` object. If provided, fees will be calculated based on the epoch. + /// * `transaction` - The GroveDB transaction argument for executing the fetch operation. + /// * `drive_operations` - A mutable reference to a vector where low-level drive operations and fees will be appended. + /// * `platform_version` - The current platform version, used to ensure compatibility. + /// + /// # Returns + /// * `Ok(Some(Arc))` if the signers' power is successfully fetched. + /// * `Ok(None)` if the signers' power does not exist. + /// * `Err(Error)` if an error occurs during the fetch operation. + /// + /// # Errors + /// * `Error::Drive(DriveError::CorruptedContractPath)` if the fetched path does not refer to a valid sum item. + /// * `Error::Drive(DriveError::CorruptedCodeExecution)` if the element type is unexpected. + /// * `Error::Drive(DriveError::NotSupportedPrivate)` if stateful batch insertions are attempted. + /// * `Error::GroveDB` for any underlying GroveDB errors. + pub(super) fn fetch_action_id_info_keep_serialized_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_path( + contract_id.as_ref(), + &group_contract_position_bytes, + action_id.as_ref(), + ); + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let value = self.grove_get_raw_item( + (&path).into(), + ACTION_INFO_KEY, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )?; + + Ok(value) + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/mod.rs new file mode 100644 index 0000000000..1268499743 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/mod.rs @@ -0,0 +1,78 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::GroupSumPower; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +mod v0; + +impl Drive { + /// Fetches the action id signers power + pub fn fetch_action_id_signers_power( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_signers_power + { + 0 => self.fetch_action_id_signers_power_v0( + contract_id, + group_contract_position, + action_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_signers_power".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + pub(crate) fn fetch_action_id_signers_power_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + estimate_costs_only: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .group + .fetch + .fetch_action_id_signers_power + { + 0 => self.fetch_action_id_signers_power_and_add_operations_v0( + contract_id, + group_contract_position, + action_id, + estimate_costs_only, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_action_id_signers_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/v0/mod.rs new file mode 100644 index 0000000000..dfd611757e --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_action_id_signers_power/v0/mod.rs @@ -0,0 +1,132 @@ +use crate::drive::group::paths::{group_action_path, ACTION_SIGNERS_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::data_contract::group::GroupSumPower; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::{TransactionArg, TreeType}; + +impl Drive { + /// v0 implementation of fetching the signers' power for a given action ID within a group contract. + /// + /// This function retrieves the signers' power associated with a specific action ID in a group contract. + /// It constructs the appropriate GroveDB path, fetches the relevant data, deserializes it, and + /// calculates any applicable fees based on the provided epoch. + /// + /// # Parameters + /// * `contract_id` - The identifier of the contract. + /// * `group_contract_position` - The position of the group contract within the data contract. + /// * `action_id` - The identifier of the action whose signers' power is to be fetched. + /// * `apply` - A boolean flag indicating whether to apply certain operations during the fetch. + /// * `transaction` - The GroveDB transaction argument for executing the fetch operation. + /// * `platform_version` - The current platform version, used to ensure compatibility. + /// + /// # Returns + /// * `Ok(Some(Arc))` if the signers' power is successfully fetched. + /// * `Ok(None)` if the signers' power does not exist. + /// * `Err(Error)` if an error occurs during the fetch operation. + /// + /// # Errors + /// * `Error::Drive(DriveError::CorruptedContractPath)` if the fetched path does not refer to a valid sum item. + /// * `Error::Drive(DriveError::CorruptedCodeExecution)` if the element type is unexpected. + /// * `Error::GroveDB` for any underlying GroveDB errors. + pub(super) fn fetch_action_id_signers_power_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_path( + contract_id.as_ref(), + &group_contract_position_bytes, + action_id.as_ref(), + ); + + let value = self + .grove_get_optional_sum_tree_total_value( + (&path).into(), + ACTION_SIGNERS_KEY, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut vec![], + &platform_version.drive, + )? + .map(|v| v as GroupSumPower); + + Ok(value) + } + + /// v0 implementation of fetching the signers' power for a given action ID within a group contract and adding related operations. + /// + /// This function not only fetches the signers' power but also appends necessary low-level drive operations based on the provided epoch. + /// It ensures that fees are calculated and added to the `drive_operations` vector when applicable. + /// + /// # Parameters + /// * `contract_id` - The identifier of the contract. + /// * `group_contract_position` - The position of the group contract within the data contract. + /// * `action_id` - The identifier of the action whose signers' power is to be fetched. + /// * `epoch` - An optional reference to an `Epoch` object. If provided, fees will be calculated based on the epoch. + /// * `transaction` - The GroveDB transaction argument for executing the fetch operation. + /// * `drive_operations` - A mutable reference to a vector where low-level drive operations and fees will be appended. + /// * `platform_version` - The current platform version, used to ensure compatibility. + /// + /// # Returns + /// * `Ok(Some(Arc))` if the signers' power is successfully fetched. + /// * `Ok(None)` if the signers' power does not exist. + /// * `Err(Error)` if an error occurs during the fetch operation. + /// + /// # Errors + /// * `Error::Drive(DriveError::CorruptedContractPath)` if the fetched path does not refer to a valid sum item. + /// * `Error::Drive(DriveError::CorruptedCodeExecution)` if the element type is unexpected. + /// * `Error::Drive(DriveError::NotSupportedPrivate)` if stateful batch insertions are attempted. + /// * `Error::GroveDB` for any underlying GroveDB errors. + pub(super) fn fetch_action_id_signers_power_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + action_id: Identifier, + estimate_costs_only: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_action_path( + contract_id.as_ref(), + &group_contract_position_bytes, + action_id.as_ref(), + ); + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimate_costs_only { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + } else { + DirectQueryType::StatefulDirectQuery + }; + + let value = self + .grove_get_optional_sum_tree_total_value( + (&path).into(), + ACTION_SIGNERS_KEY, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )? + .map(|v| v as GroupSumPower); + + Ok(value) + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_group_info/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_group_info/mod.rs new file mode 100644 index 0000000000..b67a145b52 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_group_info/mod.rs @@ -0,0 +1,103 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Fetches the `Group` for the given contract and group contract position. + /// + /// This function queries the GroveDB to fetch the `Group` associated with a specific contract + /// and group contract position. The method selects the appropriate version of + /// `fetch_group_info` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn fetch_group_info( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.fetch.fetch_group_info { + 0 => self.fetch_group_info_v0( + contract_id, + group_contract_position, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_group_info".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the `Group` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `fetch_group_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing + /// layer information used for cost estimation. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified contract ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn fetch_group_info_and_add_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.fetch.fetch_group_info { + 0 => self.fetch_group_info_and_add_operations_v0( + contract_id, + group_contract_position, + estimated_costs_only_with_layer_info, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_group_info_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_group_info/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_group_info/v0/mod.rs new file mode 100644 index 0000000000..312a6c4be7 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_group_info/v0/mod.rs @@ -0,0 +1,83 @@ +use std::collections::HashMap; + +use crate::drive::group::paths::{group_path, GROUP_INFO_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformDeserializable; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; + +impl Drive { + pub(super) fn fetch_group_info_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_path(contract_id.as_ref(), &group_contract_position_bytes); + + let maybe_group = self + .grove_get_raw_optional_item( + (&path).into(), + GROUP_INFO_KEY, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut vec![], + &platform_version.drive, + )? + .map(|value| Group::deserialize_from_bytes(&value)) + .transpose()?; + + Ok(maybe_group) + } + + pub(super) fn fetch_group_info_and_add_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + // Construct the GroveDB path for the action signers + let path = group_path(contract_id.as_ref(), &group_contract_position_bytes); + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let maybe_group = self + .grove_get_raw_optional_item( + (&path).into(), + GROUP_INFO_KEY, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )? + .map(|value| Group::deserialize_from_bytes(&value)) + .transpose()?; + + Ok(maybe_group) + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_group_infos/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_group_infos/mod.rs new file mode 100644 index 0000000000..b05c9a24a3 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_group_infos/mod.rs @@ -0,0 +1,99 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +mod v0; +impl Drive { + /// Fetches the `Group` for the given contract. + /// + /// This function queries the GroveDB to fetch the potentially many `Group`s associated with a + /// specific contract. The method selects the appropriate version of + /// `fetch_group_infos` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn fetch_group_infos( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.fetch.fetch_group_infos { + 0 => self.fetch_group_infos_v0( + contract_id, + start_group_contract_position, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_group_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the `Group` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `fetch_group_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified contract ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn fetch_group_infos_operations( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.fetch.fetch_group_infos { + 0 => self.fetch_group_infos_operations_v0( + contract_id, + start_group_contract_position, + limit, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_group_infos_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/fetch_group_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/fetch/fetch_group_infos/v0/mod.rs new file mode 100644 index 0000000000..f4b42fded4 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/fetch_group_infos/v0/mod.rs @@ -0,0 +1,79 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use dpp::serialization::PlatformDeserializable; +use dpp::version::PlatformVersion; +use grovedb::query_result_type::QueryResultType; +use grovedb::Element::Item; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_group_infos_v0( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.fetch_group_infos_operations_v0( + contract_id, + start_group_contract_position, + limit, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_group_infos_operations_v0( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Self::group_infos_for_contract_id_query( + contract_id.to_buffer(), + start_group_contract_position, + limit, + ); + + self.grove_get_raw_path_query( + &path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + drive_operations, + &platform_version.drive, + )? + .0 + .to_key_elements_btree_map() + .into_iter() + .map(|(key, element)| { + let group_contract_position: GroupContractPosition = + GroupContractPosition::from_be_bytes(key.try_into().map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "group contract position not encoded on 2 bytes as expected".to_string(), + )) + })?); + match element { + Item(value, ..) => Ok(( + group_contract_position, + Group::deserialize_from_bytes(&value)?, + )), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "token tree for infos should contain only items".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/group/fetch/mod.rs b/packages/rs-drive/src/drive/group/fetch/mod.rs new file mode 100644 index 0000000000..8df377a7a9 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/mod.rs @@ -0,0 +1,7 @@ +mod fetch_action_id_has_signer; +mod fetch_action_id_info; +mod fetch_action_id_info_keep_serialized; +mod fetch_action_id_signers_power; +mod fetch_group_info; +mod fetch_group_infos; +mod queries; diff --git a/packages/rs-drive/src/drive/group/fetch/queries.rs b/packages/rs-drive/src/drive/group/fetch/queries.rs new file mode 100644 index 0000000000..7dbd1223c5 --- /dev/null +++ b/packages/rs-drive/src/drive/group/fetch/queries.rs @@ -0,0 +1,47 @@ +use crate::drive::group::paths::group_contract_path_vec; +use crate::drive::Drive; +use crate::query::{Query, QueryItem}; +use dpp::data_contract::GroupContractPosition; +use grovedb::{PathQuery, SizedQuery}; +use std::ops::RangeFull; + +impl Drive { + /// The query for a single group info inside a contract. + pub fn group_info_for_contract_id_and_group_contract_position_query( + contract_id: [u8; 32], + group_contract_position: GroupContractPosition, + ) -> PathQuery { + let group_contract_path = group_contract_path_vec(&contract_id); + PathQuery::new_single_key( + group_contract_path, + group_contract_position.to_be_bytes().to_vec(), + ) + } + + /// The query for the group infos inside a contract. + pub fn group_infos_for_contract_id_query( + contract_id: [u8; 32], + start_at: Option<(GroupContractPosition, bool)>, + limit: Option, + ) -> PathQuery { + let group_contract_path = group_contract_path_vec(&contract_id); + let mut query = Query::new_with_direction(true); + if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeFrom(start_at.to_be_bytes().to_vec()..)) + } else { + query.insert_item(QueryItem::RangeAfter(start_at.to_be_bytes().to_vec()..)) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + PathQuery { + path: group_contract_path, + query: SizedQuery { + query, + limit, + offset: None, + }, + } + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs b/packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs new file mode 100644 index 0000000000..adfbb1c643 --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_group_action/mod.rs @@ -0,0 +1,128 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; + +use dpp::data_contract::group::GroupMemberPower; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::prelude::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Adds an action to the state + pub fn add_group_action( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + initialize_with_insert_action_info: Option, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.group.insert.add_group_action { + 0 => self.add_group_action_v0( + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_group_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds action creation operations to drive operations + pub fn add_group_action_add_to_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + initialize_with_insert_action_info: Option, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.group.insert.add_group_action { + 0 => self.add_group_action_add_to_operations_v0( + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + block_info, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_group_action_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to create a new group action + pub fn add_group_action_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + initialize_with_insert_action_info: Option, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_group_action_operations_v0( + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_group_action_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs b/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs new file mode 100644 index 0000000000..f45e9ec03c --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_group_action/v0/mod.rs @@ -0,0 +1,244 @@ +use crate::drive::group::paths::{ + group_action_path, group_action_root_path, group_action_signers_path_vec, ACTION_INFO_KEY, + ACTION_SIGNERS_KEY, +}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::{BatchInsertApplyType, BatchInsertTreeApplyType, QueryTarget}; +use crate::util::object_size_info::PathKeyInfo::PathFixedSizeKeyRef; +use crate::util::object_size_info::{DriveKeyInfo, PathKeyElementInfo}; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::group::GroupMemberPower; +use dpp::data_contract::GroupContractPosition; +use dpp::fee::fee_result::FeeResult; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformSerializable; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::element::SumValue; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; +use grovedb_epoch_based_storage_flags::StorageFlags; +use std::collections::HashMap; + +impl Drive { + pub(super) fn add_group_action_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + initialize_with_insert_action_info: Option, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations: Vec = vec![]; + self.add_group_action_add_to_operations_v0( + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + block_info, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + Ok(fees) + } + + /// Adds group creation operations to drive operations + pub(super) fn add_group_action_add_to_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + initialize_with_insert_action_info: Option, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + let batch_operations = self.add_group_action_operations( + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + block_info, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// The operations needed to create a group + pub(super) fn add_group_action_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + initialize_with_insert_action_info: Option, + action_id: Identifier, + signer_identity_id: Identifier, + signer_power: GroupMemberPower, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = vec![]; + + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Drive::add_estimation_costs_for_add_group_action( + contract_id.to_buffer(), + group_contract_position, + Some(action_id.to_buffer()), + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let group_contract_position_bytes = group_contract_position.to_be_bytes().to_vec(); + let group_action_root_path = group_action_root_path( + contract_id.as_slice(), + group_contract_position_bytes.as_slice(), + ); + let apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertTreeApplyType::StatefulBatchInsertTree + } else { + BatchInsertTreeApplyType::StatelessBatchInsertTree { + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, + flags_len: 0, + } + }; + + let storage_flags = Some(StorageFlags::new_single_epoch( + block_info.epoch.index, + Some(signer_identity_id.to_buffer()), + )); + + let element_flags = StorageFlags::map_to_some_element_flags(storage_flags.as_ref()); + + let mut inserted_root_action = false; + + if let Some(initialize_with_insert_action_info) = initialize_with_insert_action_info { + // We insert the contract root into the group tree + inserted_root_action = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKeyRef((group_action_root_path, action_id.as_slice())), + TreeType::NormalTree, + None, + apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if inserted_root_action { + let group_action_path = group_action_path( + contract_id.as_slice(), + group_contract_position_bytes.as_slice(), + action_id.as_slice(), + ); + + self.batch_insert_empty_sum_tree( + group_action_path, + DriveKeyInfo::KeyRef(ACTION_SIGNERS_KEY), + None, + &mut batch_operations, + &platform_version.drive, + )?; + + let serialized = initialize_with_insert_action_info.serialize_consume_to_bytes()?; + + self.batch_insert( + PathKeyElementInfo::PathFixedSizeKeyRefElement::<5>(( + group_action_path, + ACTION_INFO_KEY, + Element::Item(serialized, element_flags.clone()), + )), + &mut batch_operations, + &platform_version.drive, + )?; + } + } + + let signers_path = group_action_signers_path_vec( + contract_id.as_slice(), + group_contract_position, + action_id.as_slice(), + ); + + let signer_apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertApplyType::StatefulBatchInsert + } else { + BatchInsertApplyType::StatelessBatchInsert { + in_tree_type: TreeType::SumTree, + target: QueryTarget::QueryTargetValue(8), + } + }; + + if inserted_root_action { + self.batch_insert( + PathKeyElementInfo::PathKeyElement::<0>(( + signers_path, + signer_identity_id.to_vec(), + Element::SumItem(signer_power as SumValue, element_flags), + )), + &mut batch_operations, + &platform_version.drive, + )?; + } else { + // we should verify it doesn't yet exist + self.batch_insert_sum_item_if_not_exists( + PathKeyElementInfo::PathKeyElement::<0>(( + signers_path, + signer_identity_id.to_vec(), + Element::SumItem(signer_power as SumValue, element_flags), + )), + true, + signer_apply_type, + transaction, + &mut batch_operations, + &platform_version.drive, + )?; + } + + Ok(batch_operations) + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs b/packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs new file mode 100644 index 0000000000..a5fe50e545 --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_new_groups/mod.rs @@ -0,0 +1,99 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; + +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::prelude::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::{BTreeMap, HashMap}; + +mod v0; + +impl Drive { + /// Adds groups to the state. + pub fn add_new_groups( + &self, + contract_id: Identifier, + groups: &BTreeMap, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_new_groups_v0( + contract_id, + groups, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_groups".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds groups creation operations to drive operations + pub fn add_new_groups_add_to_operations( + &self, + contract_id: Identifier, + groups: &BTreeMap, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_new_groups_add_to_operations_v0( + contract_id, + groups, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_groups_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to create groups + pub fn add_new_groups_operations( + &self, + contract_id: Identifier, + groups: &BTreeMap, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.insert.add_new_groups { + 0 => self.add_new_groups_operations_v0( + contract_id, + groups, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_new_groups_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs b/packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs new file mode 100644 index 0000000000..2535d64d7a --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/add_new_groups/v0/mod.rs @@ -0,0 +1,217 @@ +use crate::drive::group::paths::{ + group_contract_path, group_path, group_root_path, GROUP_ACTIVE_ACTIONS_KEY, + GROUP_CLOSED_ACTIONS_KEY, GROUP_INFO_KEY, +}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::BatchInsertTreeApplyType; +use crate::util::object_size_info::PathKeyInfo::{PathFixedSizeKey, PathFixedSizeKeyRef}; +use crate::util::object_size_info::{DriveKeyInfo, PathKeyElementInfo}; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use dpp::serialization::PlatformSerializable; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; +use std::collections::{BTreeMap, HashMap}; + +impl Drive { + /// Adds a group by inserting a new group subtree structure to the `Identities` subtree. + pub(super) fn add_new_groups_v0( + &self, + contract_id: Identifier, + groups: &BTreeMap, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations: Vec = vec![]; + self.add_new_groups_add_to_operations_v0( + contract_id, + groups, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + Ok(fees) + } + + /// Adds group creation operations to drive operations + pub(super) fn add_new_groups_add_to_operations_v0( + &self, + contract_id: Identifier, + groups: &BTreeMap, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + let batch_operations = self.add_new_groups_operations( + contract_id, + groups, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// The operations needed to create a group + pub(super) fn add_new_groups_operations_v0( + &self, + contract_id: Identifier, + groups: &BTreeMap, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = vec![]; + + let group_tree_path = group_root_path(); + + let apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertTreeApplyType::StatefulBatchInsertTree + } else { + BatchInsertTreeApplyType::StatelessBatchInsertTree { + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, + flags_len: 0, + } + }; + + // We insert the contract root into the group tree + let inserted = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKey((group_tree_path, contract_id.to_vec())), + TreeType::NormalTree, + None, + apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if inserted { + for (group_pos, group) in groups { + let group_pos_bytes = group_pos.to_be_bytes().to_vec(); + let path = group_contract_path(contract_id.as_slice()); + self.batch_insert_empty_tree( + path, + DriveKeyInfo::Key(group_pos_bytes.clone()), + None, + &mut batch_operations, + &platform_version.drive, + )?; + let group_path = group_path(contract_id.as_slice(), group_pos_bytes.as_slice()); + + let serialized_group_info = group.serialize_to_bytes()?; + let info_item = Element::Item(serialized_group_info, None); + + self.batch_insert_empty_tree( + group_path, + DriveKeyInfo::KeyRef(GROUP_ACTIVE_ACTIONS_KEY), + None, + &mut batch_operations, + &platform_version.drive, + )?; + + self.batch_insert( + PathKeyElementInfo::PathFixedSizeKeyRefElement::<3>(( + group_path, + GROUP_INFO_KEY, + info_item, + )), + &mut batch_operations, + &platform_version.drive, + )?; + + self.batch_insert_empty_tree( + group_path, + DriveKeyInfo::KeyRef(GROUP_CLOSED_ACTIONS_KEY), + None, + &mut batch_operations, + &platform_version.drive, + )?; + } + } else { + for (group_pos, group) in groups { + let group_pos_bytes = group_pos.to_be_bytes().to_vec(); + let path = group_contract_path(contract_id.as_slice()); + let inserted = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKeyRef((path, group_pos_bytes.as_slice())), + TreeType::NormalTree, + None, + apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if inserted { + let group_path = group_path(contract_id.as_slice(), group_pos_bytes.as_slice()); + + let serialized_group_info = group.serialize_to_bytes()?; + let info_item = Element::Item(serialized_group_info, None); + + self.batch_insert_empty_tree( + group_path, + DriveKeyInfo::KeyRef(GROUP_ACTIVE_ACTIONS_KEY), + None, + &mut batch_operations, + &platform_version.drive, + )?; + + self.batch_insert( + PathKeyElementInfo::PathFixedSizeKeyRefElement::<3>(( + group_path, + GROUP_INFO_KEY, + info_item, + )), + &mut batch_operations, + &platform_version.drive, + )?; + + self.batch_insert_empty_tree( + group_path, + DriveKeyInfo::KeyRef(GROUP_CLOSED_ACTIONS_KEY), + None, + &mut batch_operations, + &platform_version.drive, + )?; + } + } + } + + Ok(batch_operations) + } +} diff --git a/packages/rs-drive/src/drive/group/insert/mod.rs b/packages/rs-drive/src/drive/group/insert/mod.rs new file mode 100644 index 0000000000..344133883d --- /dev/null +++ b/packages/rs-drive/src/drive/group/insert/mod.rs @@ -0,0 +1,2 @@ +mod add_group_action; +mod add_new_groups; diff --git a/packages/rs-drive/src/drive/group/mod.rs b/packages/rs-drive/src/drive/group/mod.rs new file mode 100644 index 0000000000..a5fec1b5de --- /dev/null +++ b/packages/rs-drive/src/drive/group/mod.rs @@ -0,0 +1,10 @@ +#[cfg(feature = "server")] +mod estimated_costs; +#[cfg(feature = "server")] +mod fetch; +#[cfg(feature = "server")] +mod insert; +/// Group paths +pub mod paths; +#[cfg(feature = "server")] +mod prove; diff --git a/packages/rs-drive/src/drive/group/paths.rs b/packages/rs-drive/src/drive/group/paths.rs new file mode 100644 index 0000000000..07449e982f --- /dev/null +++ b/packages/rs-drive/src/drive/group/paths.rs @@ -0,0 +1,256 @@ +use crate::drive::RootTree; +use dpp::data_contract::GroupContractPosition; + +// We should have +// GROUP_ACTIVE_ACTIONS_TREE +// / \ +// GROUP_INFO GROUP_CLOSED_ACTIONS_TREE + +/// The key used to identify the group information in storage. +pub const GROUP_INFO_KEY: &[u8; 1] = b"I"; +/// The key used to identify the group actions in storage. +pub const GROUP_ACTIVE_ACTIONS_KEY: &[u8; 1] = b"M"; +/// The key used to identify the group actions in storage. +pub const GROUP_CLOSED_ACTIONS_KEY: &[u8; 1] = b"X"; +/// The key used to identify the action information in storage. +pub const ACTION_INFO_KEY: &[u8; 1] = b"I"; +/// The key used to identify the action signers in storage. +pub const ACTION_SIGNERS_KEY: &[u8; 1] = b"S"; + +/// Group root path + +pub fn group_root_path() -> [&'static [u8]; 1] { + [Into::<&[u8; 1]>::into(RootTree::GroupActions)] +} + +/// Group root path vector + +pub fn group_root_path_vec() -> Vec> { + vec![vec![RootTree::GroupActions as u8]] +} + +/// Group path + +pub fn group_contract_path(contract_id: &[u8]) -> [&[u8]; 2] { + [Into::<&[u8; 1]>::into(RootTree::GroupActions), contract_id] +} + +/// Group path vector + +pub fn group_contract_path_vec(contract_id: &[u8]) -> Vec> { + vec![vec![RootTree::GroupActions as u8], contract_id.to_vec()] +} + +/// Group path + +pub fn group_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], +) -> [&'a [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + ] +} + +/// Group path vector + +pub fn group_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + ] +} + +/// Group action path + +pub fn group_action_root_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], +) -> [&'a [u8]; 4] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_ACTIVE_ACTIONS_KEY, + ] +} + +/// Group action path vector + +pub fn group_action_root_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_ACTIVE_ACTIONS_KEY.to_vec(), + ] +} + +/// Group path + +pub fn group_action_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], + action_id: &'a [u8], +) -> [&'a [u8]; 5] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_ACTIVE_ACTIONS_KEY, + action_id, + ] +} + +/// Group path vector + +pub fn group_action_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, + action_id: &[u8], +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_ACTIVE_ACTIONS_KEY.to_vec(), + action_id.to_vec(), + ] +} + +/// Group path + +pub fn group_action_signers_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], + action_id: &'a [u8], +) -> [&'a [u8]; 6] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_ACTIVE_ACTIONS_KEY, + action_id, + ACTION_SIGNERS_KEY, + ] +} + +/// Group path vector + +pub fn group_action_signers_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, + action_id: &[u8], +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_ACTIVE_ACTIONS_KEY.to_vec(), + action_id.to_vec(), + ACTION_SIGNERS_KEY.to_vec(), + ] +} + +/// Group action path + +pub fn group_closed_action_root_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], +) -> [&'a [u8]; 4] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_CLOSED_ACTIONS_KEY, + ] +} + +/// Group action path vector + +pub fn group_closed_action_root_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_CLOSED_ACTIONS_KEY.to_vec(), + ] +} + +/// Group path + +pub fn group_closed_action_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], + action_id: &'a [u8], +) -> [&'a [u8]; 5] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_CLOSED_ACTIONS_KEY, + action_id, + ] +} + +/// Group path vector + +pub fn group_closed_action_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, + action_id: &[u8], +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_CLOSED_ACTIONS_KEY.to_vec(), + action_id.to_vec(), + ] +} + +/// Group path + +pub fn group_closed_action_signers_path<'a>( + contract_id: &'a [u8], + group_contract_position_bytes: &'a [u8], + action_id: &'a [u8], +) -> [&'a [u8]; 6] { + [ + Into::<&[u8; 1]>::into(RootTree::GroupActions), + contract_id, + group_contract_position_bytes, + GROUP_CLOSED_ACTIONS_KEY, + action_id, + ACTION_SIGNERS_KEY, + ] +} + +/// Group path vector + +pub fn group_closed_action_signers_path_vec( + contract_id: &[u8], + group_contract_position: GroupContractPosition, + action_id: &[u8], +) -> Vec> { + vec![ + vec![RootTree::GroupActions as u8], + contract_id.to_vec(), + group_contract_position.to_be_bytes().to_vec(), + GROUP_CLOSED_ACTIONS_KEY.to_vec(), + action_id.to_vec(), + ACTION_SIGNERS_KEY.to_vec(), + ] +} diff --git a/packages/rs-drive/src/drive/group/prove/mod.rs b/packages/rs-drive/src/drive/group/prove/mod.rs new file mode 100644 index 0000000000..c6fa82c789 --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/mod.rs @@ -0,0 +1,2 @@ +mod prove_group_info; +mod prove_group_infos; diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs new file mode 100644 index 0000000000..5fd307c25e --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_group_info/mod.rs @@ -0,0 +1,99 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Proves the `Group` for the given contract and group contract position. + /// + /// This function queries the GroveDB to prove the `Group` associated with a specific contract + /// and group contract position. The method selects the appropriate version of + /// `prove_group_info` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn prove_group_info( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.prove.prove_group_info { + 0 => self.prove_group_info_v0( + contract_id, + group_contract_position, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_group_info".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves the `Group` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `prove_group_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to an optional `HashMap` containing + /// layer information used for cost estimation. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified contract ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn prove_group_info_operations( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.prove.prove_group_info { + 0 => self.prove_group_info_operations_v0( + contract_id, + group_contract_position, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_group_info_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs new file mode 100644 index 0000000000..0dd20e36e0 --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_group_info/v0/mod.rs @@ -0,0 +1,45 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + pub(super) fn prove_group_info_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_group_info_operations_v0( + contract_id, + group_contract_position, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_group_info_operations_v0( + &self, + contract_id: Identifier, + group_contract_position: GroupContractPosition, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Drive::group_info_for_contract_id_and_group_contract_position_query( + contract_id.to_buffer(), + group_contract_position, + ); + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs new file mode 100644 index 0000000000..27b153c2b1 --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_group_infos/mod.rs @@ -0,0 +1,99 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::group::Group; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; +use std::collections::BTreeMap; + +mod v0; +impl Drive { + /// Proves the `Group` for the given contract. + /// + /// This function queries the GroveDB to prove the potentially many `Group`s associated with a + /// specific contract. The method selects the appropriate version of + /// `prove_group_infos` based on the `platform_version` provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `transaction`: The transaction argument used for the query. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified action ID and contract position. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub fn prove_group_infos( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.prove.prove_group_infos { + 0 => self.prove_group_infos_v0( + contract_id, + start_group_contract_position, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_group_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves the `Group` and adds corresponding operations to the drive for the given action ID and group contract position. + /// + /// This function is similar to `prove_group_info` but also adds operations to the drive for state changes or queries. + /// Additionally, it supports cost estimation by interacting with the layer information if provided. + /// + /// # Parameters + /// - `contract_id`: The identifier of the contract that the action belongs to. + /// - `group_contract_position`: The position of the group contract in the data structure. + /// - `transaction`: The transaction argument used for the query. + /// - `drive_operations`: A mutable reference to a vector that stores low-level drive operations. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Group)`: The `Group` for the specified contract ID and contract position, along with any added operations. + /// - `Err(Error)`: If an error occurs, a generic error is returned. + /// + /// # Errors + /// - `DriveError::UnknownVersionMismatch`: If the `platform_version` does not match any known versions. + pub(crate) fn prove_group_infos_operations( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.group.prove.prove_group_infos { + 0 => self.prove_group_infos_operations_v0( + contract_id, + start_group_contract_position, + limit, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_group_infos_and_add_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs b/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs new file mode 100644 index 0000000000..d1260102bd --- /dev/null +++ b/packages/rs-drive/src/drive/group/prove/prove_group_infos/v0/mod.rs @@ -0,0 +1,50 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::data_contract::GroupContractPosition; +use dpp::identifier::Identifier; +use dpp::prelude::StartAtIncluded; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + pub(super) fn prove_group_infos_v0( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_group_infos_operations_v0( + contract_id, + start_group_contract_position, + limit, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_group_infos_operations_v0( + &self, + contract_id: Identifier, + start_group_contract_position: Option<(GroupContractPosition, StartAtIncluded)>, + limit: Option, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Self::group_infos_for_contract_id_query( + contract_id.to_buffer(), + start_group_contract_position, + limit, + ); + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/fetch_identity_contract_nonce/v0/mod.rs b/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/fetch_identity_contract_nonce/v0/mod.rs index 14a8e3e05e..bfbf1c2f4f 100644 --- a/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/fetch_identity_contract_nonce/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/fetch_identity_contract_nonce/v0/mod.rs @@ -12,7 +12,7 @@ use dpp::prelude::IdentityNonce; use crate::drive::identity::contract_info::ContractInfoStructure::IdentityContractNonceKey; use dpp::version::PlatformVersion; use grovedb::Element::Item; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Fetches the Identity's contract revision from the backing store @@ -51,7 +51,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, query_target: QueryTargetValue(1), } }; diff --git a/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/merge_identity_contract_nonce/v0/mod.rs b/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/merge_identity_contract_nonce/v0/mod.rs index aaa805ca54..9585f029fe 100644 --- a/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/merge_identity_contract_nonce/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/contract_info/identity_contract_nonce/merge_identity_contract_nonce/v0/mod.rs @@ -11,7 +11,7 @@ use crate::util::object_size_info::{PathKeyElementInfo, PathKeyInfo}; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; use dpp::block::block_info::BlockInfo; use dpp::fee::fee_result::FeeResult; @@ -98,8 +98,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: 0, } }; @@ -119,7 +119,7 @@ impl Drive { // we insert the contract root tree if it doesn't exist already self.batch_insert_empty_tree_if_not_exists( PathKeyInfo::<0>::PathKey((identity_path, vec![IdentityContractInfo as u8])), - false, + TreeType::NormalTree, None, apply_type, transaction, @@ -134,7 +134,7 @@ impl Drive { identity_contract_info_root_path_vec(&identity_id), contract_id.to_vec(), )), - false, + TreeType::NormalTree, None, apply_type, transaction, @@ -302,7 +302,7 @@ mod tests { use platform_version::version::PlatformVersion; fn setup_base_test(contract_id: [u8; 32]) -> (Drive, Identity) { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); let platform_version = PlatformVersion::first(); diff --git a/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs b/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs index 745bd2daff..a2177bd069 100644 --- a/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs @@ -24,7 +24,7 @@ use dpp::identity::{IdentityPublicKey, Purpose}; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; use grovedb::reference_path::ReferencePathType::{SiblingReference, UpstreamRootHeightReference}; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use grovedb_costs::OperationCost; use integer_encoding::VarInt; use std::collections::HashMap; @@ -95,8 +95,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: 0, } }; @@ -233,7 +233,7 @@ impl Drive { BatchInsertApplyType::StatefulBatchInsert } else { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, target: QueryTargetValue(reference_type_path.serialized_size() as u32), } }; @@ -419,7 +419,7 @@ impl Drive { BatchInsertApplyType::StatefulBatchInsert } else { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, target: QueryTargetValue(reference.serialized_size() as u32), } }; diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_authentication_keys_security_level_in_key_reference_tree/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_authentication_keys_security_level_in_key_reference_tree/v0/mod.rs index 28d254ead1..529b56477f 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_authentication_keys_security_level_in_key_reference_tree/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_authentication_keys_security_level_in_key_reference_tree/v0/mod.rs @@ -2,8 +2,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllItems; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::identity_query_keys_security_level_tree_path_vec; @@ -45,7 +45,7 @@ impl Drive { )), //todo: revisit EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(4), //we can estimate that each security level will only have 4 keys //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: AllItems(1, KEY_REFERENCE_SIZE, None), diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_balances/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_balances/v0/mod.rs index fd7be5dcdb..db78d1fff3 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_balances/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_balances/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::balances::balance_path_vec; @@ -56,12 +56,15 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, 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: 1, }, None, @@ -73,7 +76,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(balance_path_vec()), EstimatedLayerInformation { - is_sum_tree: true, + tree_type: TreeType::SumTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, AVERAGE_BALANCE_SIZE, None), }, diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info/v0/mod.rs index 79a3a2c57b..77a184dab7 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info/v0/mod.rs @@ -3,9 +3,9 @@ use crate::drive::{identity_tree_path, Drive}; use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllSubtrees, Mix}; use grovedb::EstimatedSumTrees::NoSumTrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; impl Drive { @@ -19,7 +19,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, @@ -29,7 +29,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(identity_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -46,7 +46,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_path_vec(identity_id.as_slice())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(2, false), estimated_layer_sizes: Mix { subtrees_size: Some((1, NoSumTrees, None, 2)), // weight of 2 because 1 for keys and 1 for data contract info @@ -59,7 +59,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_contract_info_root_path_vec(identity_id)), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group/v0/mod.rs index 9fc0347ab8..563dedebf6 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group/v0/mod.rs @@ -2,9 +2,9 @@ use crate::drive::identity::identity_contract_info_group_path_vec; use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::Mix; use grovedb::EstimatedSumTrees::NoSumTrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; impl Drive { @@ -20,7 +20,7 @@ impl Drive { group_id, )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(2), estimated_layer_sizes: Mix { subtrees_size: Some((1, NoSumTrees, None, 1)), diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_key_purpose/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_key_purpose/v0/mod.rs index 2a2d2405d7..195a04d3c7 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_key_purpose/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_key_purpose/v0/mod.rs @@ -2,8 +2,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllReference; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::estimation_costs::KEY_REFERENCE_SIZE; use crate::drive::identity::identity_contract_info_group_path_key_purpose_vec; @@ -25,7 +25,7 @@ impl Drive { key_purpose, )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(5), estimated_layer_sizes: AllReference(1, KEY_REFERENCE_SIZE, None), }, diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_keys/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_keys/v0/mod.rs index efa3892a36..069fc57bcb 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_keys/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_identity_contract_info_group_keys/v0/mod.rs @@ -2,9 +2,9 @@ use crate::drive::identity::identity_contract_info_group_keys_path_vec; use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllSubtrees; use grovedb::EstimatedSumTrees::NoSumTrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; impl Drive { @@ -20,7 +20,7 @@ impl Drive { group_id, )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(2), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_keys_for_identity_id/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_keys_for_identity_id/v0/mod.rs index 3721c5cad3..ac776f1ab2 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_keys_for_identity_id/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_keys_for_identity_id/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::{identity_tree_path, Drive}; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::{identity_key_tree_path_vec, identity_path_vec}; @@ -58,7 +58,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, @@ -68,7 +68,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(identity_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -78,7 +78,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_path_vec(identity_id.as_slice())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, false), //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), @@ -89,7 +89,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_key_tree_path_vec(identity_id.as_slice())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(50), //we can estimate that an identity will have amount 50 keys //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: AllItems(1, 42, Some(3)), diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_negative_credit/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_negative_credit/v0/mod.rs index 34a7a6d214..c4102f56b7 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_negative_credit/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_negative_credit/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::{identity_tree_path, Drive}; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllSubtrees, Mix}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::identity_path_vec; @@ -36,7 +36,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(identity_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -53,7 +53,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_path_vec(identity_id.as_slice())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(2, false), //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: Mix { diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs index 68d4852ad3..6951d86eda 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_purpose_in_key_reference_tree/v0/mod.rs @@ -2,8 +2,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllReference, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::identity_query_keys_purpose_tree_path_vec; @@ -68,7 +68,7 @@ impl Drive { purpose, )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count, // there are //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes, diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_root_key_reference_tree/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_root_key_reference_tree/v0/mod.rs index ca2672fa5a..7d312f98fd 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_root_key_reference_tree/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_root_key_reference_tree/v0/mod.rs @@ -2,8 +2,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllSubtrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::identity_query_keys_tree_path_vec; @@ -34,7 +34,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_query_keys_tree_path_vec(identity_id)), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(4), //we can estimate that an identity will have amount 50 keys //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_update_nonce/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_update_nonce/v0/mod.rs index bbd73f99ed..0f12965492 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_update_nonce/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_update_nonce/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::{identity_tree_path, Drive}; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllSubtrees, Mix}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::identity_path_vec; @@ -40,7 +40,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(0, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, @@ -50,7 +50,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(identity_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -67,7 +67,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_path_vec(identity_id.as_slice())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, false), //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: Mix { diff --git a/packages/rs-drive/src/drive/identity/estimation_costs/for_update_revision/v0/mod.rs b/packages/rs-drive/src/drive/identity/estimation_costs/for_update_revision/v0/mod.rs index f5fe620cc6..659ffc2616 100644 --- a/packages/rs-drive/src/drive/identity/estimation_costs/for_update_revision/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/estimation_costs/for_update_revision/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::{identity_tree_path, Drive}; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllSubtrees, Mix}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::identity::identity_path_vec; @@ -40,7 +40,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(0, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, @@ -50,7 +50,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(identity_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -67,7 +67,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(identity_path_vec(identity_id.as_slice())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, false), //We can mark these as all subtrees, because the revision will be under estimated_layer_sizes: Mix { diff --git a/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_balance/v0/mod.rs b/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_balance/v0/mod.rs index 2c5c98f7db..31c0eb6b9c 100644 --- a/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_balance/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_balance/v0/mod.rs @@ -12,7 +12,7 @@ use dpp::fee::Credits; use dpp::version::PlatformVersion; use grovedb::Element::SumItem; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Fetches the Identity's balance from the backing store @@ -77,7 +77,7 @@ impl Drive { } else { // 8 is the size of a i64 used in sum trees DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: true, + in_tree_type: TreeType::SumTree, query_target: QueryTargetValue(8), } }; diff --git a/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_negative_balance/v0/mod.rs b/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_negative_balance/v0/mod.rs index ba32dca874..8bc4ccb63b 100644 --- a/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_negative_balance/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/balance/fetch_identity_negative_balance/v0/mod.rs @@ -9,7 +9,7 @@ use dpp::fee::Credits; use dpp::version::PlatformVersion; use grovedb::Element::Item; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Fetches the Identity's negative balance operations from the backing store. @@ -26,7 +26,7 @@ impl Drive { } else { // 8 is the size of a encoded u64 DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: true, + in_tree_type: TreeType::SumTree, query_target: QueryTargetValue(8), } }; diff --git a/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs index 9a928d7b27..859982396a 100644 --- a/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/fetch_by_public_key_hashes/mod.rs @@ -21,7 +21,7 @@ mod tests { #[test] fn test_fetch_all_keys_on_identity() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let drive_version = &platform_version.drive; diff --git a/packages/rs-drive/src/drive/identity/fetch/nonce/fetch_identity_nonce/v0/mod.rs b/packages/rs-drive/src/drive/identity/fetch/nonce/fetch_identity_nonce/v0/mod.rs index 14a7c3f705..8aa7fbe80d 100644 --- a/packages/rs-drive/src/drive/identity/fetch/nonce/fetch_identity_nonce/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/nonce/fetch_identity_nonce/v0/mod.rs @@ -12,7 +12,7 @@ use dpp::prelude::IdentityNonce; use dpp::version::PlatformVersion; use grovedb::Element::Item; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Fetches the Identity's nonce from the backing store @@ -48,7 +48,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, query_target: QueryTargetValue(1), } }; diff --git a/packages/rs-drive/src/drive/identity/fetch/revision/fetch_identity_revision/v0/mod.rs b/packages/rs-drive/src/drive/identity/fetch/revision/fetch_identity_revision/v0/mod.rs index bc58f65524..5257b2f432 100644 --- a/packages/rs-drive/src/drive/identity/fetch/revision/fetch_identity_revision/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/fetch/revision/fetch_identity_revision/v0/mod.rs @@ -12,7 +12,7 @@ use dpp::prelude::Revision; use dpp::version::PlatformVersion; use grovedb::Element::Item; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Fetches the Identity's revision from the backing store @@ -48,7 +48,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, query_target: QueryTargetValue(1), } }; diff --git a/packages/rs-drive/src/drive/identity/insert/add_new_identity/mod.rs b/packages/rs-drive/src/drive/identity/insert/add_new_identity/mod.rs index 3494ceb37c..16f9767ef3 100644 --- a/packages/rs-drive/src/drive/identity/insert/add_new_identity/mod.rs +++ b/packages/rs-drive/src/drive/identity/insert/add_new_identity/mod.rs @@ -150,7 +150,9 @@ mod tests { let platform_version = PlatformVersion::latest(); let expected_fee_result = FeeResult { storage_fee: 128871000, - processing_fee: 2330320, + // 2 extra loaded bytes because the token tree is no longer empty + // these 2 loaded bytes cost 20 credits each + processing_fee: 2330360, ..Default::default() }; @@ -186,7 +188,7 @@ mod tests { platform_version: &PlatformVersion, expected_fee_result: FeeResult, ) { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); diff --git a/packages/rs-drive/src/drive/identity/insert/add_new_identity/v0/mod.rs b/packages/rs-drive/src/drive/identity/insert/add_new_identity/v0/mod.rs index 536d680821..9345a21a5b 100644 --- a/packages/rs-drive/src/drive/identity/insert/add_new_identity/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/insert/add_new_identity/v0/mod.rs @@ -19,7 +19,7 @@ use dpp::identity::identity_public_key::accessors::v0::{ }; use dpp::version::PlatformVersion; use grovedb::batch::KeyInfoPath; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use itertools::Itertools; use std::collections::{BTreeSet, HashMap}; @@ -122,8 +122,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags.serialized_size(), } }; @@ -131,7 +131,7 @@ impl Drive { // We insert the identity tree let inserted = self.batch_insert_empty_tree_if_not_exists( PathFixedSizeKey((identity_tree_path, id.to_vec())), - false, + TreeType::NormalTree, Some(&storage_flags), apply_type, transaction, @@ -257,7 +257,7 @@ impl Drive { let mut create_tree_keys_operations = self.create_key_tree_with_keys_operations( id.to_buffer(), public_keys.into_values().collect(), - // if we are a masternode identity, we want to register all keys as non unique + // if we are a masternode identity, we want to register all keys as non-unique is_masternode_identity, &block_info.epoch, estimated_costs_only_with_layer_info, diff --git a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs index 75466736bd..44d104288a 100644 --- a/packages/rs-drive/src/drive/identity/key/fetch/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/fetch/mod.rs @@ -1027,7 +1027,7 @@ mod tests { #[test] fn test_fetch_all_keys_on_identity() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -1063,7 +1063,7 @@ mod tests { #[test] fn test_fetch_single_identity_key() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); @@ -1103,7 +1103,7 @@ mod tests { #[test] fn test_fetch_multiple_identity_key() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); @@ -1143,7 +1143,7 @@ mod tests { #[test] fn test_fetch_unknown_identity_key_returns_not_found() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); diff --git a/packages/rs-drive/src/drive/identity/key/insert/insert_key_searchable_references/v0/mod.rs b/packages/rs-drive/src/drive/identity/key/insert/insert_key_searchable_references/v0/mod.rs index 8ae39f8b34..91fd7fbe21 100644 --- a/packages/rs-drive/src/drive/identity/key/insert/insert_key_searchable_references/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/insert/insert_key_searchable_references/v0/mod.rs @@ -16,7 +16,7 @@ use dpp::identity::{IdentityPublicKey, Purpose, SecurityLevel}; use dpp::version::drive_versions::DriveVersion; use grovedb::batch::KeyInfoPath; use grovedb::reference_path::ReferencePathType; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -79,8 +79,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: SINGLE_EPOCH_FLAGS_SIZE, } }; diff --git a/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_non_unique_public_key_hash_reference/v0/mod.rs b/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_non_unique_public_key_hash_reference/v0/mod.rs index 355d05f34b..a24e1eea04 100644 --- a/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_non_unique_public_key_hash_reference/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_non_unique_public_key_hash_reference/v0/mod.rs @@ -7,9 +7,9 @@ use crate::drive::{ use crate::util::type_constants::{DEFAULT_HASH_160_SIZE_U8, DEFAULT_HASH_SIZE_U8}; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; use grovedb::EstimatedSumTrees::NoSumTrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; impl Drive { @@ -24,7 +24,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(non_unique_key_hashes_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_160_SIZE_U8, NoSumTrees, None), }, @@ -36,7 +36,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(non_unique_key_hashes_sub_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(ESTIMATED_NON_UNIQUE_KEY_DUPLICATES), estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, 0, None), }, diff --git a/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_unique_public_key_hash_reference/v0/mod.rs b/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_unique_public_key_hash_reference/v0/mod.rs index 80a35c46de..db8a337fa4 100644 --- a/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_unique_public_key_hash_reference/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/key/insert_key_hash_identity_reference/estimation_costs/add_estimation_costs_for_insert_unique_public_key_hash_reference/v0/mod.rs @@ -5,7 +5,7 @@ use grovedb::EstimatedLayerCount::PotentiallyAtMaxElements; use grovedb::EstimatedLayerSizes::AllItems; use crate::util::type_constants::{DEFAULT_HASH_160_SIZE_U8, DEFAULT_HASH_SIZE_U32}; -use grovedb::EstimatedLayerInformation; +use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; impl Drive { @@ -18,7 +18,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(unique_key_hashes_path), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems( DEFAULT_HASH_160_SIZE_U8, diff --git a/packages/rs-drive/src/drive/identity/update/mod.rs b/packages/rs-drive/src/drive/identity/update/mod.rs index bae2413245..bffc73961e 100644 --- a/packages/rs-drive/src/drive/identity/update/mod.rs +++ b/packages/rs-drive/src/drive/identity/update/mod.rs @@ -57,7 +57,9 @@ mod tests { let platform_version = PlatformVersion::latest(); let expected_fee_result = FeeResult { storage_fee: 14202000, - processing_fee: 1098260, + // 2 extra loaded bytes because the token tree is no longer empty + // these 2 loaded bytes cost 20 credits each + processing_fee: 1098300, ..Default::default() }; @@ -81,7 +83,7 @@ mod tests { platform_version: &PlatformVersion, expected_fee_result: FeeResult, ) { - let drive = setup_drive_with_initial_state_structure(None); + let drive = setup_drive_with_initial_state_structure(Some(&platform_version)); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -143,6 +145,9 @@ mod tests { // ------------------------------------------------- // check_reference_below_tokens_cost (4 tests) + // This test exists to make sure the update cost that goes through the tokens tree + // (as key hash references are below the token tree) + // stay the same cost. // ------------------------------------------------- #[test] fn check_reference_below_tokens_cost_first_version_apply() { @@ -171,7 +176,9 @@ mod tests { let platform_version = PlatformVersion::latest(); let expected_fee_result = FeeResult { storage_fee: 9423000, - processing_fee: 406100, + // 2 extra loaded bytes because the token tree is no longer empty + // these 2 loaded bytes cost 20 credits each + processing_fee: 406140, ..Default::default() }; do_check_reference_below_tokens_cost(true, platform_version, expected_fee_result); @@ -182,7 +189,9 @@ mod tests { let platform_version = PlatformVersion::latest(); let expected_fee_result = FeeResult { storage_fee: 9423000, - processing_fee: 314560, + // 2 extra loaded bytes because the token tree is no longer empty + // these 2 loaded bytes cost 20 credits each + processing_fee: 314600, ..Default::default() }; do_check_reference_below_tokens_cost(false, platform_version, expected_fee_result); @@ -193,7 +202,7 @@ mod tests { platform_version: &PlatformVersion, expected_fee_result: FeeResult, ) { - let drive = setup_drive_with_initial_state_structure(None); + let drive = setup_drive_with_initial_state_structure(Some(platform_version)); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -302,7 +311,7 @@ mod tests { let platform_version = PlatformVersion::latest(); let expected_fee_result = FeeResult { storage_fee: 347382000, - processing_fee: 6819220, + processing_fee: 6819260, ..Default::default() }; @@ -334,7 +343,7 @@ mod tests { platform_version: &PlatformVersion, expected_fee_result: FeeResult, ) { - let drive = setup_drive_with_initial_state_structure(None); + let drive = setup_drive_with_initial_state_structure(Some(&platform_version)); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -449,7 +458,7 @@ mod tests { platform_version: &PlatformVersion, expected_fee_result: FeeResult, ) { - let drive = setup_drive_with_initial_state_structure(None); + let drive = setup_drive_with_initial_state_structure(Some(&platform_version)); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -563,7 +572,7 @@ mod tests { expected_estimated_fee_result: FeeResult, expected_fee_result: FeeResult, ) { - let drive = setup_drive_with_initial_state_structure(None); + let drive = setup_drive_with_initial_state_structure(Some(&platform_version)); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -682,7 +691,7 @@ mod tests { platform_version: &PlatformVersion, expected_fee_result: FeeResult, ) { - let drive = setup_drive_with_initial_state_structure(None); + let drive = setup_drive_with_initial_state_structure(Some(&platform_version)); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); diff --git a/packages/rs-drive/src/drive/identity/update/operations/merge_identity_nonce_operations/v0/mod.rs b/packages/rs-drive/src/drive/identity/update/operations/merge_identity_nonce_operations/v0/mod.rs index dcca501abd..5bc218428d 100644 --- a/packages/rs-drive/src/drive/identity/update/operations/merge_identity_nonce_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/update/operations/merge_identity_nonce_operations/v0/mod.rs @@ -177,7 +177,7 @@ mod tests { use platform_version::version::PlatformVersion; fn setup_base_test() -> (Drive, Identity) { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let transaction = drive.grove.start_transaction(); let platform_version = PlatformVersion::first(); diff --git a/packages/rs-drive/src/drive/initialization/mod.rs b/packages/rs-drive/src/drive/initialization/mod.rs index 97159a53ba..2c673b9024 100644 --- a/packages/rs-drive/src/drive/initialization/mod.rs +++ b/packages/rs-drive/src/drive/initialization/mod.rs @@ -2,6 +2,7 @@ mod genesis_core_height; mod v0; +mod v1; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -24,9 +25,10 @@ impl Drive { .create_initial_state_structure { 0 => self.create_initial_state_structure_0(transaction, platform_version), + 1 => self.create_initial_state_structure_1(transaction, platform_version), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "create_initial_state_structure".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive/src/drive/initialization/v0/mod.rs b/packages/rs-drive/src/drive/initialization/v0/mod.rs index ff30075d68..681a9f45d1 100644 --- a/packages/rs-drive/src/drive/initialization/v0/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v0/mod.rs @@ -20,6 +20,25 @@ impl Drive { &self, transaction: TransactionArg, platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let drive_version = &platform_version.drive; + self.create_initial_state_structure_top_level_0(transaction, platform_version)?; + + // On lower layers we can use batching + + let batch = + self.create_initial_state_structure_lower_layers_operations_0(platform_version)?; + + self.grove_apply_batch(batch, false, transaction, drive_version)?; + + Ok(()) + } + + /// Creates the initial state structure. + pub(in crate::drive::initialization) fn create_initial_state_structure_top_level_0( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, ) -> Result<(), Error> { let drive_version = &platform_version.drive; // We can not use batching to insert the root tree structure @@ -61,7 +80,7 @@ impl Drive { self.grove_insert_empty_tree( SubtreePath::empty(), - &[RootTree::TokenBalances as u8], + &[RootTree::Tokens as u8], transaction, None, &mut drive_operations, @@ -151,6 +170,14 @@ impl Drive { drive_version, )?; + Ok(()) + } + + /// Creates the initial state structure. + pub(in crate::drive::initialization) fn create_initial_state_structure_lower_layers_operations_0( + &self, + platform_version: &PlatformVersion, + ) -> Result { // On lower layers we can use batching let mut batch = GroveDbOpBatch::new(); @@ -181,9 +208,7 @@ impl Drive { // For the votes tree structure Drive::add_initial_vote_tree_main_structure_operations(&mut batch, platform_version)?; - self.grove_apply_batch(batch, false, transaction, drive_version)?; - - Ok(()) + Ok(batch) } } @@ -198,10 +223,9 @@ mod tests { use grovedb::{PathQuery, Query, SizedQuery}; #[test] - fn test_create_initial_state_structure() { - let drive = setup_drive_with_initial_state_structure(None); - - let platform_version = PlatformVersion::latest(); + fn test_create_initial_state_structure_in_first_protocol_version() { + let platform_version = PlatformVersion::first(); + let drive = setup_drive_with_initial_state_structure(Some(platform_version)); let mut query = Query::new(); query.insert_all(); @@ -227,12 +251,40 @@ mod tests { } #[test] - fn test_initial_state_structure_proper_heights() { + fn test_create_initial_state_structure_in_latest_protocol_version() { let drive = setup_drive_with_initial_state_structure(None); - let _db_transaction = drive.grove.start_transaction(); - let platform_version = PlatformVersion::latest(); + + let mut query = Query::new(); + query.insert_all(); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let (elements, _) = drive + .grove_get_raw_path_query( + &root_path_query, + None, + QueryElementResultType, + &mut drive_operations, + &platform_version.drive, + ) + .expect("expected to get root elements"); + assert_eq!(elements.len(), 14); + } + + #[test] + fn test_initial_state_structure_proper_heights_in_first_protocol_version() { + let platform_version = PlatformVersion::first(); + let drive = setup_drive_with_initial_state_structure(Some(platform_version)); + + let platform_version = PlatformVersion::first(); let drive_version = &platform_version.drive; // Merk Level 0 @@ -302,7 +354,7 @@ mod tests { // Merk Level 2 let mut query = Query::new(); - query.insert_key(vec![RootTree::TokenBalances as u8]); + query.insert_key(vec![RootTree::Tokens as u8]); let root_path_query = PathQuery::new( vec![], SizedQuery { @@ -515,4 +567,313 @@ mod tests { .expect("expected to get root elements"); assert_eq!(proof.len(), 250); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent } + + #[test] + fn test_initial_state_structure_proper_heights_in_latest_protocol_version() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + let drive_version = &platform_version.drive; + + // Merk Level 0 + let mut query = Query::new(); + query.insert_key(vec![RootTree::DataContractDocuments as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 112); //it + left + right + + // Merk Level 1 + let mut query = Query::new(); + query.insert_key(vec![RootTree::Identities as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 180); //it + left + right + parent + parent other + + let mut query = Query::new(); + query.insert_key(vec![RootTree::Balances as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 181); //it + left + right + parent + parent other + + // Merk Level 2 + let mut query = Query::new(); + query.insert_key(vec![RootTree::Tokens as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 250); //it + left + right + parent + sibling + parent sibling + grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::Pools as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 218); //it + left + parent + sibling + parent sibling + grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::WithdrawalTransactions as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 250); //it + left + right + parent + sibling + parent sibling + grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::Votes as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 250); //it + left + right + parent + sibling + parent sibling + grandparent + + // Merk Level 3 + + let mut query = Query::new(); + query.insert_key(vec![RootTree::UniquePublicKeyHashesToIdentities as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 248); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent + + let mut query = Query::new(); + query.insert_key(vec![ + RootTree::NonUniquePublicKeyKeyHashesToIdentities as u8, + ]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 248); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::PreFundedSpecializedBalances as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 217); //it + parent + parent sibling + grandparent + grandparent sibling + great-grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::SpentAssetLockTransactions as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 248); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::GroupActions as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 248); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::Misc as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 250); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent + + let mut query = Query::new(); + query.insert_key(vec![RootTree::Versions as u8]); + let root_path_query = PathQuery::new( + vec![], + SizedQuery { + query, + limit: None, + offset: None, + }, + ); + let mut drive_operations = vec![]; + let proof = drive + .grove_get_proved_path_query( + &root_path_query, + None, + &mut drive_operations, + drive_version, + ) + .expect("expected to get root elements"); + assert_eq!(proof.len(), 250); //it + parent + sibling + parent sibling + grandparent + grandparent sibling + great-grandparent + } } diff --git a/packages/rs-drive/src/drive/initialization/v1/mod.rs b/packages/rs-drive/src/drive/initialization/v1/mod.rs new file mode 100644 index 0000000000..fe70af42b2 --- /dev/null +++ b/packages/rs-drive/src/drive/initialization/v1/mod.rs @@ -0,0 +1,81 @@ +//! Drive Initialization + +use crate::drive::balances::TOTAL_TOKEN_SUPPLIES_STORAGE_KEY; +use crate::util::batch::GroveDbOpBatch; + +use crate::drive::system::misc_path_vec; +use crate::drive::tokens::paths::{ + tokens_root_path_vec, TOKEN_BALANCES_KEY, TOKEN_IDENTITY_INFO_KEY, TOKEN_STATUS_INFO_KEY, +}; +use crate::drive::{Drive, RootTree}; +use crate::error::Error; +use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; +use dpp::version::PlatformVersion; +use grovedb::{Element, TransactionArg}; +use grovedb_path::SubtreePath; + +impl Drive { + /// Creates the initial state structure. + pub(super) fn create_initial_state_structure_1( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let drive_version = &platform_version.drive; + self.create_initial_state_structure_top_level_0(transaction, platform_version)?; + + self.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::GroupActions as u8], + transaction, + None, + &mut vec![], + drive_version, + )?; + + // On lower layers we can use batching + + let mut batch = + self.create_initial_state_structure_lower_layers_operations_0(platform_version)?; + + self.initial_state_structure_lower_layers_add_operations_1(&mut batch, platform_version)?; + + self.grove_apply_batch(batch, false, transaction, drive_version)?; + + Ok(()) + } + + /// Creates the initial state structure. + pub(in crate::drive::initialization) fn initial_state_structure_lower_layers_add_operations_1( + &self, + batch: &mut GroveDbOpBatch, + _platform_version: &PlatformVersion, + ) -> Result<(), Error> { + // In Misc + batch.add_insert( + misc_path_vec(), + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY.to_vec(), + Element::empty_big_sum_tree(), + ); + + batch.add_insert( + tokens_root_path_vec(), + vec![TOKEN_BALANCES_KEY], + Element::empty_big_sum_tree(), + ); + + batch.add_insert( + tokens_root_path_vec(), + vec![TOKEN_IDENTITY_INFO_KEY], + Element::empty_tree(), + ); + + batch.add_insert( + tokens_root_path_vec(), + vec![TOKEN_STATUS_INFO_KEY], + Element::empty_tree(), + ); + + Ok(()) + } +} diff --git a/packages/rs-drive/src/drive/mod.rs b/packages/rs-drive/src/drive/mod.rs index e54d5445a2..ce1fb9a74e 100644 --- a/packages/rs-drive/src/drive/mod.rs +++ b/packages/rs-drive/src/drive/mod.rs @@ -51,9 +51,16 @@ pub mod prefunded_specialized_balances; #[cfg(any(feature = "server", feature = "verify"))] pub mod votes; +/// Group module +#[cfg(any(feature = "server", feature = "verify"))] +pub mod group; #[cfg(feature = "server")] mod shared; +/// Token module +#[cfg(any(feature = "server", feature = "verify"))] +pub mod tokens; + #[cfg(feature = "server")] use crate::cache::DriveCache; use crate::error::drive::DriveError; @@ -81,10 +88,10 @@ pub struct Drive { // DataContract_Documents 64 // / \ // Identities 32 Balances 96 -// / \ / \ -// Token_Balances 16 Pools 48 WithdrawalTransactions 80 Votes 112 -// / \ / \ / / \ -// NUPKH->I 8 UPKH->I 24 PreFundedSpecializedBalances 40 Masternode Lists 56 (reserved) SpentAssetLockTransactions 72 Misc 104 Versions 120 +// / \ / \ +// Token_Balances 16 Pools 48 WithdrawalTransactions 80 Votes 112 +// / \ / \ / \ / \ +// NUPKH->I 8 UPKH->I 24 PreFundedSpecializedBalances 40 Masternode Lists 56 (reserved) SpentAssetLockTransactions 72 GroupActions 88 Misc 104 Versions 120 /// Keys for the root tree. #[cfg(any(feature = "server", feature = "verify"))] @@ -115,12 +122,14 @@ pub enum RootTree { WithdrawalTransactions = 80, /// Balances (For identities) Balances = 96, - /// Token Balances - TokenBalances = 16, + /// Token Balances and Info + Tokens = 16, /// Versions desired by proposers Versions = 120, /// Registered votes Votes = 112, + /// Group actions + GroupActions = 88, } #[cfg(any(feature = "server", feature = "verify"))] @@ -140,9 +149,10 @@ impl fmt::Display for RootTree { RootTree::Misc => "Misc", RootTree::WithdrawalTransactions => "WithdrawalTransactions", RootTree::Balances => "Balances", - RootTree::TokenBalances => "TokenBalances", + RootTree::Tokens => "TokenBalances", RootTree::Versions => "Versions", RootTree::Votes => "Votes", + RootTree::GroupActions => "GroupActions", }; write!(f, "{}", variant_name) } @@ -183,7 +193,7 @@ impl TryFrom for RootTree { 104 => Ok(RootTree::Misc), 80 => Ok(RootTree::WithdrawalTransactions), 96 => Ok(RootTree::Balances), - 16 => Ok(RootTree::TokenBalances), + 16 => Ok(RootTree::Tokens), 120 => Ok(RootTree::Versions), 112 => Ok(RootTree::Votes), _ => Err(Error::Drive(DriveError::NotSupported( @@ -207,10 +217,11 @@ impl From for &'static [u8; 1] { RootTree::Misc => &[104], RootTree::WithdrawalTransactions => &[80], RootTree::Balances => &[96], - RootTree::TokenBalances => &[16], + RootTree::Tokens => &[16], RootTree::NonUniquePublicKeyKeyHashesToIdentities => &[8], RootTree::Versions => &[120], RootTree::Votes => &[112], + RootTree::GroupActions => &[88], } } } diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v1/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v1/mod.rs index 6a46264949..e691b12efe 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v1/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v1/mod.rs @@ -15,7 +15,7 @@ use dpp::balances::credits::MAX_CREDITS; use dpp::identifier::Identifier; use dpp::version::PlatformVersion; use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp}; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -43,7 +43,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: true, + in_tree_type: TreeType::SumTree, query_target: QueryTargetValue(8), } }; diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v1/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v1/mod.rs index 4bf03c848f..e059985c0f 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v1/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v1/mod.rs @@ -13,7 +13,7 @@ use crate::util::grove_operations::QueryTarget::QueryTargetValue; use dpp::identifier::Identifier; use dpp::version::PlatformVersion; use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp}; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -41,7 +41,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: true, + in_tree_type: TreeType::SumTree, query_target: QueryTargetValue(8), } }; diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs index c7f6b2049d..d0959b4071 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs @@ -14,7 +14,7 @@ use dpp::fee::Credits; use dpp::identifier::Identifier; use dpp::version::PlatformVersion; use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp}; -use grovedb::{EstimatedLayerInformation, TransactionArg}; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; use std::collections::HashMap; impl Drive { @@ -41,7 +41,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery } else { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: true, + in_tree_type: TreeType::SumTree, query_target: QueryTargetValue(8), } }; diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/estimation_costs/for_prefunded_specialized_balance_update/v0/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/estimation_costs/for_prefunded_specialized_balance_update/v0/mod.rs index 3400c9e6a4..5e7925cf1d 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/estimation_costs/for_prefunded_specialized_balance_update/v0/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/estimation_costs/for_prefunded_specialized_balance_update/v0/mod.rs @@ -2,8 +2,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::constants::AVERAGE_BALANCE_SIZE; use crate::drive::prefunded_specialized_balances::{ @@ -28,13 +28,16 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // We are on the 3rd level 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: 1, }, None, @@ -45,7 +48,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(prefunded_specialized_balances_path()), EstimatedLayerInformation { - is_sum_tree: true, + tree_type: TreeType::SumTree, estimated_layer_count: EstimatedLevel(0, false), estimated_layer_sizes: AllSubtrees(1, AllSumTrees, None), }, @@ -54,7 +57,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(prefunded_specialized_balances_for_voting_path_vec()), EstimatedLayerInformation { - is_sum_tree: true, + tree_type: TreeType::SumTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, AVERAGE_BALANCE_SIZE, None), }, diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/fetch/single_balance/v0/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/fetch/single_balance/v0/mod.rs index 54c2fd9690..134a05f582 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/fetch/single_balance/v0/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/fetch/single_balance/v0/mod.rs @@ -11,7 +11,7 @@ use dpp::fee::Credits; use crate::drive::prefunded_specialized_balances::prefunded_specialized_balances_for_voting_path; use dpp::version::PlatformVersion; use grovedb::Element::SumItem; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Fetches the Prefunded specialized balance from the backing store @@ -76,7 +76,7 @@ impl Drive { } else { // 8 is the size of a i64 used in sum trees DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: true, + in_tree_type: TreeType::SumTree, query_target: QueryTargetValue(8), } }; diff --git a/packages/rs-drive/src/drive/protocol_upgrade/remove_validators_proposed_app_versions/v0/mod.rs b/packages/rs-drive/src/drive/protocol_upgrade/remove_validators_proposed_app_versions/v0/mod.rs index 6db3de7a09..871e5d7bce 100644 --- a/packages/rs-drive/src/drive/protocol_upgrade/remove_validators_proposed_app_versions/v0/mod.rs +++ b/packages/rs-drive/src/drive/protocol_upgrade/remove_validators_proposed_app_versions/v0/mod.rs @@ -14,7 +14,7 @@ use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; use dpp::util::deserializer::ProtocolVersion; use dpp::version::drive_versions::DriveVersion; -use grovedb::{Element, TransactionArg}; +use grovedb::{Element, MaybeTree, TransactionArg}; use integer_encoding::VarInt; impl Drive { @@ -121,7 +121,7 @@ impl Drive { (&path).into(), validator_pro_tx_hash.as_slice(), StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, drive_operations, diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract/v0/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract/v0/mod.rs index 2257bfae60..32d25eae45 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract/v0/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract/v0/mod.rs @@ -6,8 +6,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllSubtrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::votes::paths::{ vote_contested_resource_active_polls_contract_document_tree_path, @@ -58,13 +58,16 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(2, false), //voting is on level 2 // We have balances in the middle which is a sum tree 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, @@ -76,7 +79,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_root_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // contested resource tree is a key of "c" so it should be on the top layer of the merk estimated_layer_count: EstimatedLevel(0, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), @@ -87,7 +90,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_contested_resource_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // active poll "p", with "e" and "i" first so it should be on the second layer of the merk estimated_layer_count: EstimatedLevel(1, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), @@ -98,7 +101,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_contested_resource_active_polls_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -111,7 +114,7 @@ impl Drive { contract.id_ref().as_bytes(), )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(document_type_count), estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_DOCUMENT_TYPE_NAME_SIZE, @@ -130,7 +133,7 @@ impl Drive { ), ), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(2), estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_INDEX_NAME_SIZE, @@ -148,7 +151,7 @@ impl Drive { ), ), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(1024), //Just a guess estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_INDEX_NAME_SIZE, diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs index 83f8c8dbc5..aff3c4d5fc 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs @@ -4,8 +4,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllSubtrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::votes::paths::{ vote_contested_resource_active_polls_contract_tree_path, @@ -49,13 +49,16 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(2, false), //voting is on level 2 // We have balances in the middle which is a sum tree 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, @@ -67,7 +70,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_root_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // contested resource tree is a key of "c" so it should be on the top layer of the merk estimated_layer_count: EstimatedLevel(0, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), @@ -78,7 +81,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_contested_resource_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // active poll "p", with "e" and "i" first so it should be on the second layer of the merk estimated_layer_count: EstimatedLevel(1, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), @@ -89,7 +92,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_contested_resource_active_polls_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), }, @@ -102,7 +105,7 @@ impl Drive { contract.id_ref().as_bytes(), )), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(document_type_count), estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_DOCUMENT_TYPE_NAME_SIZE, diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract/v0/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract/v0/mod.rs index 8bae767c7b..0e6e463037 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract/v0/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract/v0/mod.rs @@ -5,8 +5,8 @@ use crate::util::storage_flags::StorageFlags; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllSubtrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::contract::paths::all_contracts_global_root_path; @@ -43,7 +43,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(0, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, @@ -53,7 +53,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(all_contracts_global_root_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: PotentiallyAtMaxElements, estimated_layer_sizes: AllSubtrees( DEFAULT_HASH_SIZE_U8, diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract_document_type_excluded/v0/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract_document_type_excluded/v0/mod.rs index e9376cc385..443349d04a 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract_document_type_excluded/v0/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_levels_up_to_contract_document_type_excluded/v0/mod.rs @@ -6,8 +6,8 @@ use crate::util::storage_flags::StorageFlags; use dpp::data_contract::DataContract; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, EstimatedLevel}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::AllSubtrees; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::contract::paths::contract_root_path; use crate::error::Error; @@ -62,7 +62,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(contract_root_path(contract.id_ref().as_bytes())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(1, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, storage_flags), }, @@ -71,7 +71,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(contract_documents_path(contract.id_ref().as_bytes())), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(document_type_count), estimated_layer_sizes: AllSubtrees( ESTIMATED_AVERAGE_DOCUMENT_TYPE_NAME_SIZE, diff --git a/packages/rs-drive/src/drive/system/estimation_costs/for_total_system_credits_update/v0/mod.rs b/packages/rs-drive/src/drive/system/estimation_costs/for_total_system_credits_update/v0/mod.rs index 2d8a9d33bc..40f013d010 100644 --- a/packages/rs-drive/src/drive/system/estimation_costs/for_total_system_credits_update/v0/mod.rs +++ b/packages/rs-drive/src/drive/system/estimation_costs/for_total_system_credits_update/v0/mod.rs @@ -2,8 +2,8 @@ use crate::drive::Drive; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::{ApproximateElements, EstimatedLevel}; -use grovedb::EstimatedLayerInformation; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; use crate::drive::system::misc_path_vec; @@ -33,12 +33,15 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path([]), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(3, false), estimated_layer_sizes: AllSubtrees( 12, // about 32 + 1 + 1 / 3 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, @@ -50,7 +53,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_owned_path(misc_path_vec()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, estimated_layer_count: ApproximateElements(1), estimated_layer_sizes: AllItems(1, 8, None), }, diff --git a/packages/rs-drive/src/drive/system/genesis_time/mod.rs b/packages/rs-drive/src/drive/system/genesis_time/mod.rs index 9eee51529b..93addd701d 100644 --- a/packages/rs-drive/src/drive/system/genesis_time/mod.rs +++ b/packages/rs-drive/src/drive/system/genesis_time/mod.rs @@ -64,7 +64,7 @@ mod tests { #[test] fn should_return_none_if_cache_is_empty_and_start_time_is_not_persisted() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let result = drive .get_genesis_time(None) @@ -75,7 +75,7 @@ mod tests { #[test] fn should_return_some_if_cache_is_set() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let mut genesis_time_ms_cache = drive.cache.genesis_time_ms.write(); @@ -141,7 +141,7 @@ mod tests { #[test] fn should_set_genesis_time_to_cache() { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let genesis_time_ms: u64 = 100; diff --git a/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/mod.rs b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/mod.rs new file mode 100644 index 0000000000..53acbd6185 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/mod.rs @@ -0,0 +1,55 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::prelude::IdentityNonce; +use dpp::tokens::token_event::TokenEvent; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +mod v0; + +impl Drive { + /// Adds token transaction history + pub fn add_token_transaction_history_operations( + &self, + token_id: Identifier, + owner_id: Identifier, + owner_nonce: IdentityNonce, + event: TokenEvent, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .update + .add_transaction_history_operations + { + 0 => self.add_token_transaction_history_operations_v0( + token_id, + owner_id, + owner_nonce, + event, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_token_transaction_history_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} 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 new file mode 100644 index 0000000000..4f7a8e24c6 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/add_transaction_history_operations/v0/mod.rs @@ -0,0 +1,61 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::object_size_info::DocumentInfo::DocumentOwnedInfo; +use crate::util::object_size_info::{DocumentAndContractInfo, OwnedDocumentInfo}; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::prelude::IdentityNonce; +use dpp::tokens::token_event::TokenEvent; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +impl Drive { + /// Adds token transaction history + pub(super) fn add_token_transaction_history_operations_v0( + &self, + token_id: Identifier, + owner_id: Identifier, + owner_nonce: IdentityNonce, + event: TokenEvent, + block_info: &BlockInfo, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let contract = self.cache.system_data_contracts.load_token_history(); + + let document_type = event.associated_document_type(&contract)?; + + let document = event.build_historical_document_owned( + &contract, + token_id, + owner_id, + owner_nonce, + block_info, + )?; + + let operations = self.add_document_for_contract_operations( + DocumentAndContractInfo { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentOwnedInfo((document, None)), + owner_id: Some(owner_id.to_buffer()), + }, + contract: &contract, + document_type, + }, + true, + block_info, + &mut None, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + Ok(operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/apply_status/mod.rs b/packages/rs-drive/src/drive/tokens/apply_status/mod.rs new file mode 100644 index 0000000000..f6c88f0b68 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/apply_status/mod.rs @@ -0,0 +1,93 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::tokens::status::TokenStatus; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Sets a token status + pub fn token_apply_status( + &self, + token_id: [u8; 32], + status: TokenStatus, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.token.update.apply_status { + 0 => self.token_apply_status_v0( + token_id, + status, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_apply_status".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations to apply_status tokens without calculating fees and optionally applying. + pub fn token_apply_status_add_to_operations( + &self, + token_id: [u8; 32], + status: TokenStatus, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.token.update.apply_status { + 0 => self.token_apply_status_add_to_operations_v0( + token_id, + status, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_apply_status_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Gathers the operations needed to apply_status tokens. + pub fn token_apply_status_operations( + &self, + token_id: [u8; 32], + status: TokenStatus, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.update.apply_status { + 0 => self.token_apply_status_operations_v0( + token_id, + status, + estimated_costs_only_with_layer_info, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_apply_status_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/apply_status/v0/mod.rs b/packages/rs-drive/src/drive/tokens/apply_status/v0/mod.rs new file mode 100644 index 0000000000..3fe3526aa8 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/apply_status/v0/mod.rs @@ -0,0 +1,107 @@ +use crate::drive::tokens::paths::token_statuses_root_path; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::object_size_info::PathKeyElementInfo; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::serialization::PlatformSerializable; +use dpp::tokens::status::TokenStatus; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn token_apply_status_v0( + &self, + token_id: [u8; 32], + status: TokenStatus, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.token_apply_status_add_to_operations_v0( + token_id, + status, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn token_apply_status_add_to_operations_v0( + &self, + token_id: [u8; 32], + status: TokenStatus, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.token_apply_status_operations_v0( + token_id, + status, + &mut estimated_costs_only_with_layer_info, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn token_apply_status_operations_v0( + &self, + token_id: [u8; 32], + status: TokenStatus, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + let token_status_bytes = status.serialize_consume_to_bytes()?; + + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Self::add_estimation_costs_for_token_status_infos( + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + self.batch_insert( + PathKeyElementInfo::PathFixedSizeKeyRefElement::<2>(( + token_statuses_root_path(), + token_id.as_slice(), + Element::Item(token_status_bytes, None), + )), + &mut drive_operations, + &platform_version.drive, + )?; + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/mod.rs b/packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/mod.rs new file mode 100644 index 0000000000..ba521297a2 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/mod.rs @@ -0,0 +1,119 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::fee::Credits; + +use dpp::balances::credits::TokenAmount; +use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// The operations for adding a certain amount of credits to an identity's balance. This function is version controlled. + /// + /// # Arguments + /// + /// * `token_id` - The ID of the Token. + /// * `identity_id` - The ID of the Identity to which credits are to be added. + /// * `balance_to_add` - The amount of credits to be added to the identity's balance. + /// * `block_info` - Information about the current block. + /// * `apply` - A boolean indicating whether the operation should be applied or not. + /// * `transaction` - The transaction information related to the operation. + /// * `platform_version` - The platform version. + /// * `previous_fee_versions` - Cached fee versions, if any. + /// + /// # Returns + /// + /// * `Result` - The resulting fee result if successful, or an error. + pub fn add_to_identity_token_balance( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_add: Credits, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + previous_fee_versions: Option<&CachedEpochIndexFeeVersions>, + ) -> Result { + match platform_version + .drive + .methods + .token + .update + .add_to_identity_token_balance + { + 0 => self.add_to_identity_token_balance_v0( + token_id, + identity_id, + balance_to_add, + block_info, + apply, + transaction, + platform_version, + previous_fee_versions, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_to_identity_token_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds a specified amount of credits to an identity balance. This function checks for overflows and ensures the balance does not exceed `MAX_CREDITS`. + /// Balances are stored under the identity's ID in the token balance tree. + /// + /// # Arguments + /// + /// * `token_id` - The ID of the Token. + /// * `identity_id` - The ID of the Identity to which credits are to be added. + /// * `balance_to_add` - The amount of credits to be added to the identity's balance. + /// * `estimated_costs_only_with_layer_info` - Estimated costs with layer information, if any. + /// * `transaction` - The transaction information related to the operation. + /// * `platform_version` - The platform version. + /// + /// # Returns + /// + /// * `Result, Error>` - The resulting low level drive operations if successful, or an error. + pub(crate) fn add_to_identity_token_balance_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_add: TokenAmount, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .update + .add_to_identity_token_balance + { + 0 => self.add_to_identity_token_balance_operations_v0( + token_id, + identity_id, + balance_to_add, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_to_identity_token_balance_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/v0/mod.rs new file mode 100644 index 0000000000..87fd0c9c37 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/add_to_previous_token_balance/v0/mod.rs @@ -0,0 +1,141 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::fee::Credits; + +use crate::drive::tokens::paths::token_balances_path_vec; +use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::version::PlatformVersion; +use dpp::ProtocolError; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Adds specified amount of credits to identity balance + /// This function checks for overflows and does not exceed MAX_CREDITS + /// + /// Balances are stored in the balance tree under the identity's id + pub(in crate::drive::tokens) fn add_to_identity_token_balance_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_add: Credits, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + previous_fee_versions: Option<&CachedEpochIndexFeeVersions>, + ) -> Result { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + let batch_operations = self.add_to_identity_token_balance_operations_v0( + token_id, + identity_id, + balance_to_add, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + let mut drive_operations: Vec = vec![]; + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + &mut drive_operations, + &platform_version.drive, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + previous_fee_versions, + )?; + Ok(fees) + } + + /// Adds specified amount of credits to identity balance + /// This function checks for overflows and does not exceed MAX_CREDITS + /// + /// Balances are stored in the identity under key 0 + /// This gets operations based on apply flag (stateful vs stateless) + pub(in crate::drive::tokens) fn add_to_identity_token_balance_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_add: TokenAmount, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Self::add_estimation_costs_for_token_balances( + token_id, + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let apply = estimated_costs_only_with_layer_info.is_none(); + + let previous_balance = if apply { + self.fetch_identity_token_balance_operations( + token_id, + identity_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )? + } else { + None // worse case is that we insert + }; + + let balance_path = token_balances_path_vec(token_id); + + if let Some(previous_balance) = previous_balance { + // Check for overflow + let new_balance = (previous_balance as i64) + .checked_add(balance_to_add as i64) + .ok_or(ProtocolError::CriticalCorruptedCreditsCodeExecution( + "Overflow of total token balance".to_string(), + ))?; + + drive_operations.push(LowLevelDriveOperation::replace_for_known_path_key_element( + balance_path, + identity_id.to_vec(), + Element::new_sum_item(new_balance), + )); + } else { + if balance_to_add > i64::MAX as u64 { + return Err( + ProtocolError::CriticalCorruptedCreditsCodeExecution(format!( + "Token balance to add over i64 max, is {}", + balance_to_add + )) + .into(), + ); + } + drive_operations.push(LowLevelDriveOperation::insert_for_known_path_key_element( + balance_path, + identity_id.to_vec(), + Element::new_sum_item(balance_to_add as i64), + )); + } + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/mod.rs new file mode 100644 index 0000000000..9e45812091 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/mod.rs @@ -0,0 +1,152 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::Identifier; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + /// Fetches the token balances of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose balances are to be fetched. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding balances, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identities_token_balances( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identities_token_balances + { + 0 => self.fetch_identities_token_balances_v0( + token_id, + identity_ids, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token balances with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to fetch the balances for. + /// * `identity_id` - The identity's ID whose balances are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result<((BTreeMap<[u8; 32], Option>), FeeResult), Error>` - A tuple containing a map of token balances and the associated fee result. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identities_token_balances_with_costs( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(BTreeMap>, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identities_token_balances_operations( + token_id, + identity_ids, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to fetch the identity's token balances from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the balances for. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding balances, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identities_token_balances_operations( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identities_token_balances + { + 0 => self.fetch_identities_token_balances_operations_v0( + token_id, + identity_ids, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identities_token_balances_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/v0/mod.rs new file mode 100644 index 0000000000..b9dddc6e8c --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identities_token_balances/v0/mod.rs @@ -0,0 +1,63 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::Element::SumItem; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_identities_token_balances_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + self.fetch_identities_token_balances_operations_v0( + token_id, + identity_ids, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_identities_token_balances_operations_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let path_query = Self::token_balances_for_identity_ids_query(token_id, identity_ids); + + self.grove_get_raw_path_query_with_optional( + &path_query, + false, + transaction, + drive_operations, + &platform_version.drive, + )? + .into_iter() + .map(|(_, key, element)| { + let identity_id: Identifier = key.try_into().map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "identity id not 32 bytes".to_string(), + )) + })?; + match element { + Some(SumItem(value, ..)) => Ok((identity_id, Some(value as TokenAmount))), + None => Ok((identity_id, None)), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "token tree for balances should contain only sum items".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/mod.rs new file mode 100644 index 0000000000..8b563ae97b --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/mod.rs @@ -0,0 +1,135 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::fee::Credits; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the Identity's token balance from the backing store. + /// Passing `apply = false` will return estimated costs (0 or Some(0) in place of actual values). + /// + /// # Arguments + /// + /// * `token_id` - The ID of the token. + /// * `identity_id` - The ID of the Identity whose token balance is to be fetched. + /// * `apply` - Whether to actually fetch from state (true) or estimate costs (false). + /// * `transaction` - The current transaction. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - The token balance of the Identity if successful, or an error. + pub fn fetch_identity_token_balance( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_balance + { + 0 => self.fetch_identity_token_balance_v0( + token_id, + identity_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the Identity's token balance with costs (if `apply = true`) and returns associated fee result. + pub fn fetch_identity_token_balance_with_costs( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Option, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identity_token_balance_operations( + token_id, + identity_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the operations to get Identity's token balance from the backing store. + /// If `apply` is false, the operations are stateless and only used for cost estimation. + /// + /// # Arguments + /// + /// * `token_id` - The ID of the token. + /// * `identity_id` - The ID of the Identity whose token balance is to be fetched. + /// * `apply` - Whether to fetch actual stateful data (true) or just estimate costs (false). + /// * `transaction` - The current transaction. + /// * `drive_operations` - The drive operations vector to populate. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - The token balance of the Identity if successful, or an error. + pub fn fetch_identity_token_balance_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_balance + { + 0 => self.fetch_identity_token_balance_operations_v0( + token_id, + identity_id, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_balance_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/v0/mod.rs new file mode 100644 index 0000000000..3a85fb330a --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balance/v0/mod.rs @@ -0,0 +1,83 @@ +use crate::drive::tokens::paths::token_balances_path; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::Element::SumItem; +use grovedb::{TransactionArg, TreeType}; + +impl Drive { + pub(super) fn fetch_identity_token_balance_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.fetch_identity_token_balance_operations_v0( + token_id, + identity_id, + true, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_identity_token_balance_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let direct_query_type = if apply { + DirectQueryType::StatefulDirectQuery + } else { + // 8 is the size of an i64 used in sum trees + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::SumTree, + query_target: QueryTargetValue(8), + } + }; + + let balance_path = token_balances_path(&token_id); + + match self.grove_get_raw_optional( + (&balance_path).into(), + identity_id.as_slice(), + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + ) { + Ok(Some(SumItem(balance, _))) if balance >= 0 => Ok(Some(balance as TokenAmount)), + + Ok(None) | Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) => { + // If we are applying (stateful), no balance means None. + // If we are estimating (stateless), return Some(0) to indicate no cost or minimal cost scenario. + if apply { + Ok(None) + } else { + Ok(Some(0)) + } + } + + Ok(Some(SumItem(..))) => Err(Error::Drive(DriveError::CorruptedElementType( + "identity token balance was present but was negative", + ))), + + Ok(Some(_)) => Err(Error::Drive(DriveError::CorruptedElementType( + "identity token balance was present but was not a sum item", + ))), + + Err(e) => Err(e), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/mod.rs new file mode 100644 index 0000000000..fbe2b3aa43 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/mod.rs @@ -0,0 +1,151 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + /// Fetches the token balances of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose balances are to be fetched. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding balances, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identity_token_balances( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_balances + { + 0 => self.fetch_identity_token_balances_v0( + token_ids, + identity_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token balances with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to fetch the balances for. + /// * `identity_id` - The identity's ID whose balances are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result<((BTreeMap<[u8; 32], Option>), FeeResult), Error>` - A tuple containing a map of token balances and the associated fee result. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identity_token_balances_with_costs( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(BTreeMap<[u8; 32], Option>, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identity_token_balances_operations( + token_ids, + identity_id, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to fetch the identity's token balances from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the balances for. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding balances, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identity_token_balances_operations( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_balances + { + 0 => self.fetch_identity_token_balances_operations_v0( + token_ids, + identity_id, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_balances_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs new file mode 100644 index 0000000000..8084608b81 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs @@ -0,0 +1,83 @@ +use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_BALANCES_KEY}; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::Element::SumItem; +use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_identity_token_balances_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + self.fetch_identity_token_balances_operations_v0( + token_ids, + identity_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_identity_token_balances_operations_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let tokens_root = tokens_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![vec![TOKEN_BALANCES_KEY], identity_id.to_vec()]); + + let path_query = PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ); + + self.grove_get_raw_path_query_with_optional( + &path_query, + false, + transaction, + drive_operations, + &platform_version.drive, + )? + .into_iter() + .map(|(path, _, element)| { + let token_id: [u8; 32] = path + .get(1) + .ok_or(Error::Drive(DriveError::CorruptedDriveState( + "returned path item should always have a second part at index 1".to_string(), + )))? + .clone() + .try_into() + .map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "token id not 32 bytes".to_string(), + )) + })?; + match element { + Some(SumItem(value, ..)) => Ok((token_id, Some(value as TokenAmount))), + None => Ok((token_id, None)), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "token tree for balances should contain only sum items".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/mod.rs b/packages/rs-drive/src/drive/tokens/balance/mod.rs new file mode 100644 index 0000000000..33d22088c3 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/mod.rs @@ -0,0 +1,17 @@ +#[cfg(feature = "server")] +mod add_to_previous_token_balance; +#[cfg(feature = "server")] +mod fetch_identities_token_balances; +#[cfg(feature = "server")] +mod fetch_identity_token_balance; +#[cfg(feature = "server")] +mod fetch_identity_token_balances; +#[cfg(feature = "server")] +mod prove_identities_token_balances; +#[cfg(feature = "server")] +mod prove_identity_token_balances; +mod queries; +#[cfg(feature = "server")] +mod remove_from_identity_token_balance; +#[cfg(feature = "server")] +mod update; diff --git a/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/mod.rs b/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/mod.rs new file mode 100644 index 0000000000..4549f680a0 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/mod.rs @@ -0,0 +1,149 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Proves the token balances of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose balances are to be proveed. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identities_token_balances( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identities_token_balances + { + 0 => self.prove_identities_token_balances_v0( + token_id, + identity_ids, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identity_token_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves the identity's token balances with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to prove the balances for. + /// * `identity_id` - The identity's ID whose balances are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identities_token_balances_with_costs( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Vec, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.prove_identities_token_balances_operations( + token_id, + identity_ids, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to prove the identity's token balances from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the balances for. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identities_token_balances_operations( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identities_token_balances + { + 0 => self.prove_identities_token_balances_operations_v0( + token_id, + identity_ids, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identities_token_balances_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs new file mode 100644 index 0000000000..d25dc8fe16 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/prove_identities_token_balances/v0/mod.rs @@ -0,0 +1,359 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + pub(super) fn prove_identities_token_balances_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_identities_token_balances_operations_v0( + token_id, + identity_ids, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_identities_token_balances_operations_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Self::token_balances_for_identity_ids_query(token_id, identity_ids); + + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::balances::credits::TokenAmount; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::v1::DataContractV1; + use dpp::identity::Identity; + use std::collections::BTreeMap; + + use dpp::identity::accessors::IdentityGettersV0; + use dpp::prelude::DataContract; + use dpp::version::PlatformVersion; + + #[test] + fn should_prove_a_single_identity_token_balance() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + drive + .token_mint( + token_id.to_buffer(), + identity.id().to_buffer(), + 10000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token"); + let proof = drive + .prove_identities_token_balances_v0( + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!( + proved_identity_balance, + BTreeMap::from([(identity_id, Some(10000))]) + ); + } + + #[test] + fn should_prove_a_single_identity_token_balance_does_not_exist() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + let proof = drive + .prove_identities_token_balances_v0( + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!( + proved_identity_balance, + BTreeMap::from([(identity_id, None)]) + ); + } + + #[test] + fn should_prove_multiple_identity_single_token_balances_after_transfer() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id().to_buffer(); + + let identity_2 = Identity::random_identity(3, Some(15), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity_1.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .add_new_identity( + identity_2.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + drive + .token_mint( + token_id.to_buffer(), + identity_1.id().to_buffer(), + 100000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token"); + + drive + .token_transfer( + token_id.to_buffer(), + identity_1.id().to_buffer(), + identity_2.id().to_buffer(), + 30000, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to transfer token"); + let proof = drive + .prove_identities_token_balances_v0( + token_id.to_buffer(), + &vec![identity_1.id().to_buffer(), identity_2.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity_1.id().to_buffer(), identity_2.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!( + proved_identity_balance, + BTreeMap::from([(identity_1_id, Some(70000)), (identity_2_id, Some(30000))]) + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/mod.rs b/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/mod.rs new file mode 100644 index 0000000000..429bb59949 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/mod.rs @@ -0,0 +1,149 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the token balances of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose balances are to be proveed. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identity_token_balances( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identity_token_balances + { + 0 => self.prove_identity_token_balances_v0( + token_ids, + identity_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identity_token_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token balances with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to prove the balances for. + /// * `identity_id` - The identity's ID whose balances are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identity_token_balances_with_costs( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Vec, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.prove_identity_token_balances_operations( + token_ids, + identity_id, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to prove the identity's token balances from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the balances for. + /// * `identity_id` - The ID of the identity whose token balances are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identity_token_balances_operations( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identity_token_balances + { + 0 => self.prove_identity_token_balances_operations_v0( + token_ids, + identity_id, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identity_token_balances_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs new file mode 100644 index 0000000000..621e42c370 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs @@ -0,0 +1,55 @@ +use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_BALANCES_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::PlatformVersion; +use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; + +impl Drive { + pub(super) fn prove_identity_token_balances_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_identity_token_balances_operations_v0( + token_ids, + identity_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_identity_token_balances_operations_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let tokens_root = tokens_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![vec![TOKEN_BALANCES_KEY], identity_id.to_vec()]); + + let path_query = PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ); + + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/queries.rs b/packages/rs-drive/src/drive/tokens/balance/queries.rs new file mode 100644 index 0000000000..d15202311a --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/queries.rs @@ -0,0 +1,72 @@ +use crate::drive::tokens::paths::token_balances_path_vec; +use crate::drive::Drive; +use crate::query::{Query, QueryItem}; +use grovedb::{PathQuery, SizedQuery}; +use std::ops::RangeFull; + +impl Drive { + /// The query for proving the identities balance of a token from an identity id. + pub fn token_balance_for_identity_id_query( + token_id: [u8; 32], + identity_id: [u8; 32], + ) -> PathQuery { + let balance_path = token_balances_path_vec(token_id); + PathQuery::new_single_key(balance_path, identity_id.to_vec()) + } + + /// The query getting a token balance for many identities + pub fn token_balances_for_identity_ids_query( + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + ) -> PathQuery { + let balance_path = token_balances_path_vec(token_id); + let mut query = Query::new(); + query.insert_keys(identity_ids.iter().map(|key| key.to_vec()).collect()); + PathQuery { + path: balance_path, + query: SizedQuery { + query, + limit: Some(identity_ids.len() as u16), + offset: None, + }, + } + } + + /// The query getting token balances for identities in a range + pub fn token_balances_for_range_query( + token_id: [u8; 32], + start_at: Option<([u8; 32], bool)>, + ascending: bool, + limit: u16, + ) -> PathQuery { + let balance_path = token_balances_path_vec(token_id); + let mut query = Query::new_with_direction(ascending); + if ascending { + if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeFrom(start_at.to_vec()..)) + } else { + query.insert_item(QueryItem::RangeAfter(start_at.to_vec()..)) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + } else if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeToInclusive(..=start_at.to_vec())) + } else { + query.insert_item(QueryItem::RangeTo(..start_at.to_vec())) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + PathQuery { + path: balance_path, + query: SizedQuery { + query, + limit: Some(limit), + offset: None, + }, + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/mod.rs b/packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/mod.rs new file mode 100644 index 0000000000..c80eb72789 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/mod.rs @@ -0,0 +1,117 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::fee::Credits; + +use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// The operations for removing a certain amount of credits from an identity's balance. This function is version controlled. + /// + /// # Arguments + /// + /// * `token_id` - The ID of the Token. + /// * `identity_id` - The ID of the Identity from whose balance credits are to be removed. + /// * `balance_to_remove` - The amount of credits to be removed from the identity's balance. + /// * `block_info` - Information about the current block. + /// * `apply` - A boolean indicating whether the operation should be applied or not. + /// * `transaction` - The transaction information related to the operation. + /// * `drive_version` - The drive version. + /// + /// # Returns + /// + /// * `Result` - The resulting fee result if successful, or an error. + pub fn remove_from_identity_token_balance( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_remove: Credits, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + previous_fee_versions: Option<&CachedEpochIndexFeeVersions>, + ) -> Result { + match platform_version + .drive + .methods + .token + .update + .remove_from_identity_token_balance + { + 0 => self.remove_from_identity_token_balance_v0( + token_id, + identity_id, + balance_to_remove, + block_info, + apply, + transaction, + platform_version, + previous_fee_versions, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "remove_from_identity_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Removes a specified amount of credits from an identity balance. This function doesn't allow the balance to go below zero. + /// Balances are stored under key 0 in the identity. Operations are determined based on the `apply` flag (stateful vs stateless). + /// + /// # Arguments + /// + /// * `token_id` - The ID of the Token. + /// * `identity_id` - The ID of the Identity from which credits are to be removed. + /// * `balance_to_remove` - The amount of credits to be removed from the identity's balance. + /// * `estimated_costs_only_with_layer_info` - Estimated costs with layer information, if any. + /// * `transaction` - The transaction information related to the operation. + /// * `drive_version` - The drive version. + /// + /// # Returns + /// + /// * `Result, Error>` - The resulting low level drive operations if successful, or an error. + pub(crate) fn remove_from_identity_token_balance_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_remove: Credits, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .update + .remove_from_identity_token_balance + { + 0 => self.remove_from_identity_token_balance_operations_v0( + token_id, + identity_id, + balance_to_remove, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "remove_from_identity_token_balance_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/v0/mod.rs new file mode 100644 index 0000000000..6d09ae621d --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/remove_from_identity_token_balance/v0/mod.rs @@ -0,0 +1,129 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::identity::IdentityError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::MAX_CREDITS; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::fee::Credits; + +use crate::drive::tokens::paths::token_balances_path_vec; +use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Balances are stored in the balance tree under the identity's id + pub(in crate::drive::tokens) fn remove_from_identity_token_balance_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_remove: Credits, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + previous_fee_versions: Option<&CachedEpochIndexFeeVersions>, + ) -> Result { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + let batch_operations = self.remove_from_identity_token_balance_operations_v0( + token_id, + identity_id, + balance_to_remove, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + let mut drive_operations: Vec = vec![]; + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + &mut drive_operations, + &platform_version.drive, + )?; + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + previous_fee_versions, + )?; + Ok(fees) + } + + /// Removes specified amount of credits from identity balance + /// This function doesn't go below nil balance (negative balance) + /// + /// Balances are stored in the identity under key 0 + /// This gets operations based on apply flag (stateful vs stateless) + pub(in crate::drive::tokens) fn remove_from_identity_token_balance_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + balance_to_remove: Credits, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Self::add_estimation_costs_for_token_balances( + token_id, + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let apply = estimated_costs_only_with_layer_info.is_none(); + + let previous_balance = if apply { + self.fetch_identity_token_balance_operations( + token_id, + identity_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )? + .ok_or(Error::Drive(DriveError::CorruptedCodeExecution( + "there should always be a balance if apply is set to true", + )))? + } else { + MAX_CREDITS + }; + + // we do not have enough balance + // there is a part we absolutely need to pay for + if balance_to_remove > previous_balance { + return Err(Error::Identity(IdentityError::IdentityInsufficientBalance( + format!( + "identity with token balance {} does not have the required balance to remove {}", + previous_balance, balance_to_remove + ), + ))); + } + + let balance_path = token_balances_path_vec(token_id); + + drive_operations.push(LowLevelDriveOperation::replace_for_known_path_key_element( + balance_path, + identity_id.to_vec(), + Element::new_sum_item((previous_balance - balance_to_remove) as i64), + )); + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/update.rs b/packages/rs-drive/src/drive/tokens/balance/update.rs new file mode 100644 index 0000000000..dc7c94e3e7 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/balance/update.rs @@ -0,0 +1,896 @@ +#[cfg(test)] +mod tests { + + use dpp::prelude::*; + + use crate::error::drive::DriveError; + use crate::error::Error; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use crate::util::test_helpers::test_utils::identities::create_test_identity; + use dpp::block::epoch::Epoch; + use dpp::identity::accessors::IdentityGettersV0; + + mod add_to_identity_balance { + use dpp::block::block_info::BlockInfo; + use dpp::fee::fee_result::FeeResult; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::version::PlatformVersion; + + use crate::fees::op::LowLevelDriveOperation; + + use super::*; + + #[test] + fn should_add_to_balance() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(12345), platform_version) + .expect("expected a random identity"); + + let old_balance = identity.balance(); + + let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + + drive + .add_new_identity( + identity.clone(), + false, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to insert identity"); + + let db_transaction = drive.grove.start_transaction(); + + let amount = 300; + + let fee_result = drive + .add_to_identity_balance( + identity.id().to_buffer(), + amount, + &block_info, + true, + Some(&db_transaction), + platform_version, + ) + .expect("expected to add to identity balance"); + + assert_eq!( + fee_result, + FeeResult { + processing_fee: 174660, + removed_bytes_from_system: 0, + ..Default::default() + } + ); + + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + + let (balance, _fee_cost) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block_info, + true, + None, + platform_version, + ) + .expect("expected to get balance"); + + assert_eq!(balance.unwrap(), old_balance + amount); + } + + #[test] + fn should_fail_if_balance_is_not_persisted() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + + let result = drive.add_to_identity_balance( + [0; 32], + 300, + &block_info, + true, + None, + platform_version, + ); + + assert!( + matches!(result, Err(Error::Drive(DriveError::CorruptedCodeExecution(m))) if m == "there should always be a balance") + ); + } + + #[test] + fn should_deduct_from_debt_if_balance_is_nil() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(1), None, platform_version) + .expect("expected an identity"); + + let added_balance = 300; + let negative_amount = 100; + + // Persist negative balance + let batch = vec![drive + .update_identity_negative_credit_operation( + identity.id().to_buffer(), + negative_amount, + platform_version, + ) + .expect("expected to get an update_identity_negative_credit_operation")]; + + let mut drive_operations: Vec = vec![]; + drive + .apply_batch_low_level_drive_operations( + None, + None, + batch, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should apply batch"); + + let block_info = BlockInfo::default(); + + let fee_result = drive + .add_to_identity_balance( + identity.id().to_buffer(), + added_balance, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to add to identity balance"); + + assert_eq!( + fee_result, + FeeResult { + storage_fee: 0, + processing_fee: 385160, + removed_bytes_from_system: 0, + ..Default::default() + } + ); + + let (updated_balance, _fee_cost) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block_info, + true, + None, + platform_version, + ) + .expect("expected to get balance"); + + assert_eq!( + updated_balance.expect("balance should present"), + added_balance - negative_amount + ); + + let updated_negative_balance = drive + .fetch_identity_negative_balance_operations( + identity.id().to_buffer(), + true, + None, + &mut drive_operations, + platform_version, + ) + .expect("expected to get balance") + .expect("balance should present"); + + assert_eq!(updated_negative_balance, 0) + } + + #[test] + fn should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower() { + let drive = setup_drive_with_initial_state_structure(None); + let platform_version = PlatformVersion::latest(); + let identity = create_test_identity(&drive, [0; 32], Some(1), None, platform_version) + .expect("expected an identity"); + + let added_balance = 50; + let negative_amount = 100; + + // Persist negative balance + let batch = vec![drive + .update_identity_negative_credit_operation( + identity.id().to_buffer(), + negative_amount, + platform_version, + ) + .expect("expected to get an update_identity_negative_credit_operation")]; + + let mut drive_operations: Vec = vec![]; + drive + .apply_batch_low_level_drive_operations( + None, + None, + batch, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should apply batch"); + + let block_info = BlockInfo::default(); + + let fee_result = drive + .add_to_identity_balance( + identity.id().to_buffer(), + added_balance, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to add to identity balance"); + + assert_eq!( + fee_result, + FeeResult { + storage_fee: 0, + processing_fee: 260540, + removed_bytes_from_system: 0, + ..Default::default() + } + ); + + let (updated_balance, _fee_cost) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block_info, + true, + None, + platform_version, + ) + .expect("expected to get balance"); + + assert_eq!(updated_balance.expect("balance should present"), 0); + + let updated_negative_balance = drive + .fetch_identity_negative_balance_operations( + identity.id().to_buffer(), + true, + None, + &mut drive_operations, + platform_version, + ) + .expect("expected to get balance") + .expect("balance should present"); + + assert_eq!(updated_negative_balance, negative_amount - added_balance) + } + + #[test] + fn should_estimate_costs_without_state() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(12345), platform_version) + .expect("expected a random identity"); + + let block = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + + let app_hash_before = drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .expect("should return app hash"); + + let fee_result = drive + .add_to_identity_balance( + identity.id().to_buffer(), + 300, + &block, + false, + None, + platform_version, + ) + .expect("expected to get estimated costs to update an identity balance"); + + assert_eq!( + fee_result, + FeeResult { + processing_fee: 4278840, + ..Default::default() + } + ); + + let app_hash_after = drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .expect("should return app hash"); + + assert_eq!(app_hash_after, app_hash_before); + + let (balance, _fee_cost) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block, + true, + None, + platform_version, + ) + .expect("expected to get balance"); + + assert!(balance.is_none()); //shouldn't have changed + } + } + + mod remove_from_identity_balance { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::fee::fee_result::FeeResult; + use dpp::version::PlatformVersion; + + #[test] + fn should_remove_from_balance() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(12345), platform_version) + .expect("expected a random identity"); + + let old_balance = identity.balance(); + + let block = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + + drive + .add_new_identity( + identity.clone(), + false, + &block, + true, + None, + platform_version, + ) + .expect("expected to insert identity"); + + let db_transaction = drive.grove.start_transaction(); + + let amount = 10; + + let fee_result = drive + .remove_from_identity_balance( + identity.id().to_buffer(), + amount, + &block, + true, + Some(&db_transaction), + platform_version, + None, + ) + .expect("expected to add to identity balance"); + + assert_eq!( + fee_result, + FeeResult { + processing_fee: 174660, + removed_bytes_from_system: 0, + ..Default::default() + } + ); + + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + + let (balance, _fee_cost) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block, + true, + None, + platform_version, + ) + .expect("expected to get balance"); + + assert_eq!(balance.unwrap(), old_balance - amount); + } + + #[test] + fn should_estimated_costs_without_state() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(5, Some(12345), platform_version) + .expect("expected a random identity"); + + let block = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + + let app_hash_before = drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .expect("should return app hash"); + + let amount = 10; + + let fee_result = drive + .remove_from_identity_balance( + identity.id().to_buffer(), + amount, + &block, + false, + None, + platform_version, + None, + ) + .expect("expected to add to identity balance"); + + let app_hash_after = drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .expect("should return app hash"); + + assert_eq!(app_hash_after, app_hash_before); + + assert_eq!( + fee_result, + FeeResult { + processing_fee: 2476860, + ..Default::default() + } + ); + + let (balance, _fee_cost) = drive + .fetch_identity_balance_with_costs( + identity.id().to_buffer(), + &block, + true, + None, + platform_version, + ) + .expect("expected to get balance"); + + assert!(balance.is_none()); //shouldn't have changed + } + } + + mod apply_balance_change_from_fee_to_identity_operations { + use super::*; + use crate::error::identity::IdentityError; + use crate::fees::op::LowLevelDriveOperation; + use dpp::block::block_info::BlockInfo; + use dpp::fee::epoch::{CreditsPerEpoch, GENESIS_EPOCH_INDEX}; + use dpp::fee::fee_result::refunds::{CreditsPerEpochByIdentifier, FeeRefunds}; + use dpp::fee::fee_result::FeeResult; + use dpp::fee::{Credits, SignedCredits}; + use dpp::version::PlatformVersion; + use grovedb::batch::GroveOp; + use grovedb::Element; + use nohash_hasher::IntMap; + use std::collections::BTreeMap; + + #[test] + fn should_do_nothing_if_there_is_no_balance_change() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + + let fee_result = FeeResult::default_with_fees(0, 0); + let fee_change = fee_result.clone().into_balance_change(identity.id()); + + let (drive_operations, fee_result_outcome) = drive + .apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ) + .expect("should apply fee change"); + + assert_eq!(drive_operations.len(), 0); + assert_eq!(fee_result_outcome, fee_result); + } + + #[test] + fn should_add_to_balance() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + let other_identity = + create_test_identity(&drive, [1; 32], Some(16), None, platform_version) + .expect("expected to create an identity"); + + let removed_credits = 100000; + let other_removed_credits = 200000; + + let credits_per_epoch: CreditsPerEpoch = + IntMap::from_iter([(GENESIS_EPOCH_INDEX, removed_credits)]); + + let other_credits_per_epoch: CreditsPerEpoch = + IntMap::from_iter([(GENESIS_EPOCH_INDEX, other_removed_credits)]); + + let refunds_per_epoch_by_identifier: CreditsPerEpochByIdentifier = + BTreeMap::from_iter([ + (identity.id().to_buffer(), credits_per_epoch), + (other_identity.id().to_buffer(), other_credits_per_epoch), + ]); + + let fee_result = FeeResult { + fee_refunds: FeeRefunds(refunds_per_epoch_by_identifier), + ..Default::default() + }; + let fee_change = fee_result.clone().into_balance_change(identity.id()); + + let (drive_operations, fee_result_outcome) = drive + .apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ) + .expect("should apply fee change"); + + assert!(matches!( + drive_operations[..], + [ + _, + _, + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::SumItem(refund_amount, None), + }, + .. + }), + .., + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::SumItem(other_refund_amount, None), + }, + .. + }) + ] if refund_amount as Credits == removed_credits && other_refund_amount as Credits == other_removed_credits + )); + + assert_eq!(fee_result_outcome, fee_result); + } + + #[test] + fn should_fail_if_balance_is_not_persisted() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let fee_result = FeeResult::default_with_fees(100000, 100); + let fee_change = fee_result.into_balance_change([0; 32].into()); + + let result = drive.apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ); + + assert!( + matches!(result, Err(Error::Drive(DriveError::CorruptedCodeExecution(m))) if m == "there should always be a balance if apply is set to true") + ); + } + + #[test] + fn should_deduct_from_debt_if_balance_is_nil() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let removed_credits = 10000; + let negative_amount = 1000; + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + + // Persist negative balance + let batch = vec![drive + .update_identity_negative_credit_operation( + identity.id().to_buffer(), + negative_amount, + platform_version, + ) + .expect("expected to get an update_identity_negative_credit_operation")]; + + let mut drive_operations: Vec = vec![]; + drive + .apply_batch_low_level_drive_operations( + None, + None, + batch, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should apply batch"); + + let credits_per_epoch: CreditsPerEpoch = + IntMap::from_iter([(GENESIS_EPOCH_INDEX, removed_credits)]); + + let refunds_per_epoch_by_identifier: CreditsPerEpochByIdentifier = + BTreeMap::from_iter([(identity.id().to_buffer(), credits_per_epoch)]); + + let fee_result = FeeResult { + fee_refunds: FeeRefunds(refunds_per_epoch_by_identifier), + ..Default::default() + }; + let fee_change = fee_result.clone().into_balance_change(identity.id()); + + let (drive_operations, fee_result_outcome) = drive + .apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ) + .expect("should apply fee change"); + + assert!(matches!( + &drive_operations[..], + [ + _, + _, + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::SumItem(refund_amount, None), + }, + .. + }), + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::Item(debt_bytes, None), + }, + .. + }) + ] if *refund_amount as Credits == removed_credits - negative_amount && debt_bytes == &0u64.to_be_bytes() + )); + + assert_eq!(fee_result_outcome, fee_result); + } + + #[test] + fn should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let removed_credits = 1000; + let negative_amount = 3000; + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + + // Persist negative balance + let batch = vec![drive + .update_identity_negative_credit_operation( + identity.id().to_buffer(), + negative_amount, + platform_version, + ) + .expect("expected to get an update_identity_negative_credit_operation")]; + + let mut drive_operations: Vec = vec![]; + drive + .apply_batch_low_level_drive_operations( + None, + None, + batch, + &mut drive_operations, + &platform_version.drive, + ) + .expect("should apply batch"); + + let credits_per_epoch: CreditsPerEpoch = + IntMap::from_iter([(GENESIS_EPOCH_INDEX, removed_credits)]); + + let refunds_per_epoch_by_identifier: CreditsPerEpochByIdentifier = + BTreeMap::from_iter([(identity.id().to_buffer(), credits_per_epoch)]); + + let fee_result = FeeResult { + fee_refunds: FeeRefunds(refunds_per_epoch_by_identifier), + ..Default::default() + }; + let fee_change = fee_result.clone().into_balance_change(identity.id()); + + let (drive_operations, fee_result_outcome) = drive + .apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ) + .expect("should apply fee change"); + + assert!(matches!( + &drive_operations[..], + [ + _, + _, + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::Item(debt_bytes, None), + }, + .. + }) + ] if debt_bytes == &2000u64.to_be_bytes() + )); + + assert_eq!(fee_result_outcome, fee_result); + } + + #[test] + fn should_remove_from_balance_less_amount() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + + let initial_balance = 100; + + drive + .add_to_identity_balance( + identity.id().to_buffer(), + initial_balance, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("should set initial balance"); + + let processing_fee = 20; + let storage_fee = 10; + + let fee_result = FeeResult { + processing_fee, + storage_fee, + ..Default::default() + }; + + let fee_change = fee_result.clone().into_balance_change(identity.id()); + + let (drive_operations, fee_result_outcome) = drive + .apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ) + .expect("should apply fee change"); + + assert!(matches!( + drive_operations[..], + [_, LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::SumItem(balance, None), + }, + .. + })] if balance == (initial_balance - storage_fee - processing_fee) as SignedCredits + )); + + assert_eq!(fee_result_outcome, fee_result); + } + + #[test] + fn should_remove_from_balance_bigger_amount_and_get_into_debt() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + + let initial_balance = 100; + + drive + .add_to_identity_balance( + identity.id().to_buffer(), + initial_balance, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("should set initial balance"); + + let processing_fee = 110; + let storage_fee = 80; + + let fee_result = FeeResult { + processing_fee, + storage_fee, + ..Default::default() + }; + + let fee_change = fee_result.into_balance_change(identity.id()); + + let (drive_operations, fee_result_outcome) = drive + .apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ) + .expect("should apply fee change"); + + let expected_debt_bytes = + (storage_fee + processing_fee - initial_balance).to_be_bytes(); + + assert!(matches!( + &drive_operations[..], + [ + _, + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::SumItem(balance, None), + }, + .. + }), + LowLevelDriveOperation::GroveOperation(grovedb::batch::QualifiedGroveDbOp { + op: GroveOp::Replace { + element: Element::Item(debt_bytes, None), + }, + .. + }) + ] if balance == &(0 as SignedCredits) && debt_bytes == &expected_debt_bytes + )); + + assert_eq!( + fee_result_outcome, + FeeResult { + storage_fee, + processing_fee: initial_balance - storage_fee, + ..Default::default() + } + ); + } + + #[test] + fn should_return_error_if_required_amount_bigger_than_balance() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = create_test_identity(&drive, [0; 32], Some(15), None, platform_version) + .expect("expected to create an identity"); + + let processing_fee = 110; + let storage_fee = 80; + + let fee_result = FeeResult { + processing_fee, + storage_fee, + ..Default::default() + }; + + let fee_change = fee_result.into_balance_change(identity.id()); + + let result = drive.apply_balance_change_from_fee_to_identity_operations( + fee_change, + None, + platform_version, + ); + + assert!(matches!( + result, + Err(Error::Identity(IdentityError::IdentityInsufficientBalance( + _ + ))) + )); + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/burn/mod.rs b/packages/rs-drive/src/drive/tokens/burn/mod.rs new file mode 100644 index 0000000000..e7c733df77 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/burn/mod.rs @@ -0,0 +1,100 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Burns tokens by reducing the total supply and removing them from an identity's balance. + pub fn token_burn( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + burn_amount: u64, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.token.update.burn { + 0 => self.token_burn_v0( + token_id, + identity_id, + burn_amount, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_burn".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations to burn tokens without calculating fees and optionally applying. + pub fn token_burn_add_to_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + burn_amount: u64, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.token.update.burn { + 0 => self.token_burn_add_to_operations_v0( + token_id, + identity_id, + burn_amount, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_burn_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Gathers the operations needed to burn tokens. + pub fn token_burn_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + burn_amount: u64, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.update.burn { + 0 => self.token_burn_operations_v0( + token_id, + identity_id, + burn_amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_burn_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/burn/v0/mod.rs b/packages/rs-drive/src/drive/tokens/burn/v0/mod.rs new file mode 100644 index 0000000000..3beb0c5e06 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/burn/v0/mod.rs @@ -0,0 +1,108 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn token_burn_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + burn_amount: u64, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.token_burn_add_to_operations_v0( + token_id, + identity_id, + burn_amount, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn token_burn_add_to_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + burn_amount: u64, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.token_burn_operations_v0( + token_id, + identity_id, + burn_amount, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn token_burn_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + burn_amount: u64, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + drive_operations.extend(self.remove_from_identity_token_balance_operations( + token_id, + identity_id, + burn_amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + + drive_operations.extend(self.remove_from_token_total_supply_operations( + token_id, + burn_amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs new file mode 100644 index 0000000000..8799421a9d --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs @@ -0,0 +1,42 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::balances::total_tokens_balance::TotalTokensBalance; +use dpp::version::drive_versions::DriveVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Calculates the total credits balance. + /// + /// This function verifies that the sum tree identity credits + pool credits + refunds are equal to the total credits in the system. + /// + /// # Arguments + /// + /// * `transaction` - A `TransactionArg` object representing the transaction to be used for calculating the total credits balance. + /// * `drive_version` - A `DriveVersion` object specifying the version of the Drive. + /// + /// # Returns + /// + /// * `Result` - If successful, returns a `TotalTokensBalance` object representing the total tokens balance. + /// If an error occurs during the calculation, returns an `Error`. + /// + /// # Errors + /// + /// This function will return an error if the version of the Drive is unknown. + pub fn calculate_total_tokens_balance( + &self, + transaction: TransactionArg, + drive_version: &DriveVersion, + ) -> Result { + match drive_version.methods.token.calculate_total_tokens_balance { + 0 => self.calculate_total_tokens_balance_v0(transaction, drive_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "calculate_total_tokens_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs new file mode 100644 index 0000000000..6cefd4ce28 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs @@ -0,0 +1,47 @@ +use crate::drive::balances::TOTAL_TOKEN_SUPPLIES_STORAGE_KEY; +use crate::drive::system::misc_path; +use crate::drive::tokens::paths::{tokens_root_path, TOKEN_BALANCES_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::util::grove_operations::DirectQueryType; +use dpp::balances::total_tokens_balance::TotalTokensBalance; +use dpp::version::drive_versions::DriveVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Verify that the sum tree identity credits + pool credits + refunds are equal to the + /// Total credits in the system + #[inline(always)] + pub(super) fn calculate_total_tokens_balance_v0( + &self, + transaction: TransactionArg, + drive_version: &DriveVersion, + ) -> Result { + let mut drive_operations = vec![]; + let path_holding_total_credits = misc_path(); + let total_tokens_in_platform = self.grove_get_big_sum_tree_total_value( + (&path_holding_total_credits).into(), + TOTAL_TOKEN_SUPPLIES_STORAGE_KEY, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + drive_version, + )?; + + let tokens_root_path = tokens_root_path(); + + let total_identity_token_balances = self.grove_get_big_sum_tree_total_value( + (&tokens_root_path).into(), + &[TOKEN_BALANCES_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + drive_version, + )?; + + Ok(TotalTokensBalance { + total_tokens_in_platform, + total_identity_token_balances, + }) + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/mod.rs new file mode 100644 index 0000000000..fcce3e3dff --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/mod.rs @@ -0,0 +1,57 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::drive_versions::DriveVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerInformation; +use std::collections::HashMap; + +impl Drive { + /// Adds estimation costs for token balance changes based on the provided drive version. + /// + /// This method updates the `estimated_costs_only_with_layer_info` HashMap with entries + /// representing the estimated costs for different layers of the balance tree. The method + /// adjusts its behavior depending on the provided `drive_version`, allowing it to support + /// different versioned implementations for cost estimation. + /// + /// # Parameters + /// - `token_id`: A 32-byte identifier for the token whose balance changes are being estimated. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to a HashMap that holds + /// `KeyInfoPath` and `EstimatedLayerInformation` for each token balance layer. + /// - `drive_version`: The version of the drive to determine which estimation logic to apply. + /// + /// # Returns + /// - `Ok(())` if the operation is successful. + /// - `Err(DriveError::UnknownVersionMismatch)` if the provided `drive_version` does not match + /// any known supported versions. + /// + /// # Errors + /// This function will return an error if the provided `drive_version` does not match a known version. + pub(crate) fn add_estimation_costs_for_token_balances( + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut HashMap, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .methods + .identity + .cost_estimation + .for_token_balances + { + 0 => { + Self::add_estimation_costs_for_token_balances_v0( + token_id, + estimated_costs_only_with_layer_info, + ); + Ok(()) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_estimation_costs_for_token_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/v0/mod.rs new file mode 100644 index 0000000000..6a466b9d94 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_balances/v0/mod.rs @@ -0,0 +1,102 @@ +use crate::drive::constants::AVERAGE_BALANCE_SIZE; + +use crate::drive::Drive; + +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; +use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; + +use crate::drive::tokens::paths::{ + token_balances_path, token_balances_root_path, tokens_root_path, +}; +use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; +use grovedb::EstimatedSumTrees::{AllBigSumTrees, AllSumTrees, NoSumTrees}; +use std::collections::HashMap; + +pub const ESTIMATED_TOKEN_INFO_SIZE_BYTES: u32 = 256; + +impl Drive { + /// Adds estimation costs for token balances in Drive for version 0. + /// + /// This function provides a mechanism to estimate the costs of token balances + /// in the drive by updating the provided `HashMap` with layer information + /// relevant to balances. + /// + /// # Parameters + /// + /// * `estimated_costs_only_with_layer_info`: A mutable reference to a `HashMap` + /// that stores estimated layer information based on the key information path. + /// + /// # Notes + /// + /// The function estimates costs for three layers: + /// + /// 1. **Top Layer**: + /// - Contains general balance information and is assumed to be located on + /// layer 3 (third level in the hierarchy). The update will involve modifying: + /// - 1 normal tree for token balances. + /// - 1 normal tree for identities. + /// - 1 normal tree for contract/documents. + /// + /// 2. **Token Balances or Info Layer**: + /// - This layer contains two nodes, either for representing the token balances or info. + /// + /// 3. **All Token Balances Layer**: + /// - This layer contains the token balance root path and is considered to be + /// a normal tree that will require updates to an average of 10 nodes. + /// + /// 3. **Token Layer**: + /// - This layer contains the contract-specific token balance information, which + /// is a sum tree structure with all token amounts for all identities that have a balance. + /// ``` + pub(super) fn add_estimation_costs_for_token_balances_v0( + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut HashMap, + ) { + // 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 (token balances) + // 1 normal tree (identities) + // 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(2, false), + estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), + }, + ); + + // there is one tree for the root path + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(tokens_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(0, false), // this should be at the top + estimated_layer_sizes: AllSubtrees(1, AllBigSumTrees, None), + }, + ); + + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(token_balances_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::BigSumTree, + estimated_layer_count: EstimatedLevel(10, false), // we can estimate 10 levels deep + estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, AllSumTrees, None), + }, + ); + + // this is where the balances are + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(token_balances_path(&token_id)), + EstimatedLayerInformation { + tree_type: TreeType::SumTree, + estimated_layer_count: PotentiallyAtMaxElements, + estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, AVERAGE_BALANCE_SIZE, None), + }, + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/mod.rs new file mode 100644 index 0000000000..a5225fa37b --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/mod.rs @@ -0,0 +1,57 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::drive_versions::DriveVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerInformation; +use std::collections::HashMap; + +impl Drive { + /// Adds estimation costs for token identity infos changes based on the provided drive version. + /// + /// This method updates the `estimated_costs_only_with_layer_info` HashMap with entries + /// representing the estimated costs for different layers of the balance tree. The method + /// adjusts its behavior depending on the provided `drive_version`, allowing it to support + /// different versioned implementations for cost estimation. + /// + /// # Parameters + /// - `token_id`: A 32-byte identifier for the token whose balance changes are being estimated. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to a HashMap that holds + /// `KeyInfoPath` and `EstimatedLayerInformation` for each token balance layer. + /// - `drive_version`: The version of the drive to determine which estimation logic to apply. + /// + /// # Returns + /// - `Ok(())` if the operation is successful. + /// - `Err(DriveError::UnknownVersionMismatch)` if the provided `drive_version` does not match + /// any known supported versions. + /// + /// # Errors + /// This function will return an error if the provided `drive_version` does not match a known version. + pub(crate) fn add_estimation_costs_for_token_identity_infos( + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut HashMap, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .methods + .identity + .cost_estimation + .for_token_identity_infos + { + 0 => { + Self::add_estimation_costs_for_token_identity_infos_v0( + token_id, + estimated_costs_only_with_layer_info, + ); + Ok(()) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_estimation_costs_for_token_identity_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/v0/mod.rs new file mode 100644 index 0000000000..087fa60b8f --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_identity_infos/v0/mod.rs @@ -0,0 +1,81 @@ +use crate::drive::Drive; + +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::{EstimatedLevel, PotentiallyAtMaxElements}; +use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; + +use crate::drive::tokens::paths::{ + token_identity_infos_path, token_identity_infos_root_path, tokens_root_path, +}; +use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; +use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; +use std::collections::HashMap; + +pub const ESTIMATED_TOKEN_INFO_SIZE_BYTES: u32 = 32; + +impl Drive { + pub(super) fn add_estimation_costs_for_token_identity_infos_v0( + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut HashMap, + ) { + // 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 (token balances) + // 1 normal tree (identities) + // 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(2, false), + estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), + }, + ); + + // there is one tree for the root path + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(tokens_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(1, false), // this should be at the top + estimated_layer_sizes: AllSubtrees( + 1, + SomeSumTrees { + sum_trees_weight: 0, + big_sum_trees_weight: 1, + count_trees_weight: 0, + count_sum_trees_weight: 0, + non_sum_trees_weight: 1, + }, + None, + ), + }, + ); + + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(token_identity_infos_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), // we can estimate 10 levels deep + estimated_layer_sizes: AllSubtrees(DEFAULT_HASH_SIZE_U8, NoSumTrees, None), + }, + ); + + // this is where the balances are + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(token_identity_infos_path(&token_id)), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: PotentiallyAtMaxElements, + estimated_layer_sizes: AllItems( + DEFAULT_HASH_SIZE_U8, + ESTIMATED_TOKEN_INFO_SIZE_BYTES, + None, + ), + }, + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/mod.rs new file mode 100644 index 0000000000..59cb58e546 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/mod.rs @@ -0,0 +1,55 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::drive_versions::DriveVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerInformation; +use std::collections::HashMap; + +impl Drive { + /// Adds estimation costs for token status infos changes based on the provided drive version. + /// + /// This method updates the `estimated_costs_only_with_layer_info` HashMap with entries + /// representing the estimated costs for different layers of the balance tree. The method + /// adjusts its behavior depending on the provided `drive_version`, allowing it to support + /// different versioned implementations for cost estimation. + /// + /// # Parameters + /// - `token_id`: A 32-byte identifier for the token whose balance changes are being estimated. + /// - `estimated_costs_only_with_layer_info`: A mutable reference to a HashMap that holds + /// `KeyInfoPath` and `EstimatedLayerInformation` for each token balance layer. + /// - `drive_version`: The version of the drive to determine which estimation logic to apply. + /// + /// # Returns + /// - `Ok(())` if the operation is successful. + /// - `Err(DriveError::UnknownVersionMismatch)` if the provided `drive_version` does not match + /// any known supported versions. + /// + /// # Errors + /// This function will return an error if the provided `drive_version` does not match a known version. + pub(crate) fn add_estimation_costs_for_token_status_infos( + estimated_costs_only_with_layer_info: &mut HashMap, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .methods + .identity + .cost_estimation + .for_token_identity_infos + { + 0 => { + Self::add_estimation_costs_for_token_status_infos_v0( + estimated_costs_only_with_layer_info, + ); + Ok(()) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_estimation_costs_for_token_status_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/v0/mod.rs new file mode 100644 index 0000000000..58aa341787 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_status_infos/v0/mod.rs @@ -0,0 +1,68 @@ +use crate::drive::Drive; + +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::EstimatedLevel; +use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; + +use crate::drive::tokens::paths::{token_statuses_root_path, tokens_root_path}; +use crate::util::type_constants::DEFAULT_HASH_SIZE_U8; +use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; +use std::collections::HashMap; + +pub const ESTIMATED_TOKEN_STATUS_INFO_SIZE_BYTES: u32 = 32; + +impl Drive { + pub(super) fn add_estimation_costs_for_token_status_infos_v0( + estimated_costs_only_with_layer_info: &mut HashMap, + ) { + // 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 (token balances) + // 1 normal tree (identities) + // 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(2, false), + estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), + }, + ); + + // there is one tree for the root path + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(tokens_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(1, false), // this should be at the top + estimated_layer_sizes: AllSubtrees( + 1, + SomeSumTrees { + sum_trees_weight: 0, + big_sum_trees_weight: 1, + count_trees_weight: 0, + count_sum_trees_weight: 0, + non_sum_trees_weight: 1, + }, + None, + ), + }, + ); + + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(token_statuses_root_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), // we can estimate 10 levels deep + estimated_layer_sizes: AllItems( + DEFAULT_HASH_SIZE_U8, + ESTIMATED_TOKEN_STATUS_INFO_SIZE_BYTES, + None, + ), + }, + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/mod.rs new file mode 100644 index 0000000000..51e3fc30f2 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/mod.rs @@ -0,0 +1,50 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::drive_versions::DriveVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerInformation; +use std::collections::HashMap; + +impl Drive { + /// Adds estimation costs for token total supply changes. + /// + /// It operates on the provided HashMap, `estimated_costs_only_with_layer_info`, and adds + /// new entries to it, representing the estimated costs for different layers of the balance tree. + /// + /// # Parameters + /// - `estimated_costs_only_with_layer_info`: A mutable reference to a HashMap storing + /// the `KeyInfoPath` and `EstimatedLayerInformation`. + /// + /// # Returns + /// - `Ok(())` if successful. + /// - `Err(DriveError::UnknownVersionMismatch)` if the method version doesn't match any known versions. + /// + /// # Errors + /// This function will return an error if the method version doesn't match any known versions. + pub(crate) fn add_estimation_costs_for_token_total_supply( + estimated_costs_only_with_layer_info: &mut HashMap, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .methods + .identity + .cost_estimation + .for_token_total_supply + { + 0 => { + Self::add_estimation_costs_for_token_total_supply_v0( + estimated_costs_only_with_layer_info, + ); + Ok(()) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_estimation_costs_for_token_total_supply".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/v0/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/v0/mod.rs new file mode 100644 index 0000000000..7f022ceec8 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/for_token_total_supply/v0/mod.rs @@ -0,0 +1,101 @@ +use crate::drive::Drive; + +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::EstimatedLevel; +use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; + +use crate::drive::balances::total_tokens_root_supply_path; +use crate::drive::system::misc_path; +use crate::util::type_constants::{DEFAULT_HASH_SIZE_U8, U64_SIZE_U32}; +use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; +use std::collections::HashMap; + +impl Drive { + /// Adds estimation costs for token total supply in Drive for version 0. + /// + /// This function estimates the storage and update costs associated with token total supply + /// in Drive, providing detailed information about the layer structure and required updates + /// for each relevant path. The provided `HashMap` will be updated with the estimated costs + /// for each layer involved in the process. + /// + /// # Parameters + /// + /// * `estimated_costs_only_with_layer_info`: A mutable reference to a `HashMap` + /// that stores the estimated layer information for each key information path. + /// This map will be populated with the relevant layer information for the token supply + /// data and other associated trees. + /// + /// # Notes + /// + /// The function estimates costs for the following layers: + /// + /// 1. **Top Layer**: + /// - Contains general balance information and is assumed to be located on + /// level 3 of the hierarchy. It involves updating: + /// - 1 normal tree for contract/documents. + /// - 1 sum tree for balances. + /// - 1 normal for votes. + /// - 1 normal tree for misc. + /// - This layer has an equal weight distribution between normal and sum trees. + /// + /// 2. **Misc Layer**: + /// - A normal tree that contains miscellaneous data relevant to the total supply + /// process. + /// + /// 3. **Total Tokens Root Supply Path**: + /// - This path represents the root for the total tokens supply and is updated + /// with the corresponding token supply information. It is estimated to update + /// an average of 10 nodes in a normal tree structure. + pub(super) fn add_estimation_costs_for_token_total_supply_v0( + estimated_costs_only_with_layer_info: &mut HashMap, + ) { + // we have constructed the top layer so contract/documents tree are at the top + // since balance will be on layer 4 (level 3 on right, then right, then left) + // updating will mean we will update: + // 1 normal tree (misc) + // 1 normal tree (votes) + // 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), + // 17 because we have 2 layers at 32 and two layers at 2 + estimated_layer_sizes: AllSubtrees( + 17, + SomeSumTrees { + sum_trees_weight: 1, + big_sum_trees_weight: 0, + count_trees_weight: 0, + count_sum_trees_weight: 0, + non_sum_trees_weight: 3, + }, + None, + ), + }, + ); + + // in the misc tree + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(misc_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(2, false), + estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), + }, + ); + + // in the total tokens root supply path + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(total_tokens_root_supply_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_sizes: AllItems(DEFAULT_HASH_SIZE_U8, U64_SIZE_U32, None), + }, + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/estimated_costs/mod.rs b/packages/rs-drive/src/drive/tokens/estimated_costs/mod.rs new file mode 100644 index 0000000000..8028de5375 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/estimated_costs/mod.rs @@ -0,0 +1,11 @@ +/// Module for handling operations related to token balances. +pub mod for_token_balances; + +/// Module for handling operations related to token total supply. +pub mod for_token_total_supply; + +/// Module for handling operations related to token identity information. +pub mod for_token_identity_infos; + +/// Module for handling operations related to token status information. +pub mod for_token_status_infos; diff --git a/packages/rs-drive/src/drive/tokens/freeze/mod.rs b/packages/rs-drive/src/drive/tokens/freeze/mod.rs new file mode 100644 index 0000000000..d2339bd4c8 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/freeze/mod.rs @@ -0,0 +1,95 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::Identifier; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Burns tokens by reducing the total supply and removing them from an identity's balance. + pub fn token_freeze( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.token.update.freeze { + 0 => self.token_freeze_v0( + token_id, + frozen_identity_id, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_freeze".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations to freeze tokens without calculating fees and optionally applying. + pub fn token_freeze_add_to_operations( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.token.update.freeze { + 0 => self.token_freeze_add_to_operations_v0( + token_id, + frozen_identity_id, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_freeze_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Gathers the operations needed to freeze tokens. + pub fn token_freeze_operations( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.update.freeze { + 0 => self.token_freeze_operations_v0( + token_id, + frozen_identity_id, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_freeze_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/freeze/v0/mod.rs b/packages/rs-drive/src/drive/tokens/freeze/v0/mod.rs new file mode 100644 index 0000000000..e36c612077 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/freeze/v0/mod.rs @@ -0,0 +1,147 @@ +use crate::drive::tokens::paths::token_identity_infos_path; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, Element, EstimatedLayerInformation, TransactionArg, TreeType}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn token_freeze_v0( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.token_freeze_add_to_operations_v0( + token_id, + frozen_identity_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn token_freeze_add_to_operations_v0( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.token_freeze_operations_v0( + token_id, + frozen_identity_id, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn token_freeze_operations_v0( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Self::add_estimation_costs_for_token_identity_infos( + token_id.to_buffer(), + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let token_info_path = token_identity_infos_path(token_id.as_bytes()); + match self + .grove_get_raw_optional_item( + (&token_info_path).into(), + frozen_identity_id.as_slice(), + direct_query_type, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .map(|bytes| IdentityTokenInfo::deserialize_from_bytes(&bytes)) + .transpose()? + { + None => { + let identity_token_info_bytes = + IdentityTokenInfo::new(true, platform_version)?.serialize_consume_to_bytes()?; + drive_operations.push(LowLevelDriveOperation::insert_for_known_path_key_element( + token_info_path.iter().map(|a| a.to_vec()).collect(), + frozen_identity_id.to_vec(), + Element::new_item(identity_token_info_bytes), + )); + } + Some(mut token_info) => { + if !token_info.frozen() { + token_info.set_frozen(true); + let identity_token_info_bytes = token_info.serialize_consume_to_bytes()?; + drive_operations.push( + LowLevelDriveOperation::replace_for_known_path_key_element( + token_info_path.iter().map(|a| a.to_vec()).collect(), + frozen_identity_id.to_vec(), + Element::new_item(identity_token_info_bytes), + ), + ); + } + } + }; + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/mod.rs new file mode 100644 index 0000000000..33fac51df9 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/mod.rs @@ -0,0 +1,151 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + /// Fetches the token infos of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose infos are to be fetched. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding infos, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identities_token_infos( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identities_token_infos + { + 0 => self.fetch_identities_token_infos_v0( + token_id, + identity_ids, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token infos with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to fetch the infos for. + /// * `identity_id` - The identity's ID whose infos are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result<((BTreeMap<[u8; 32], Option>), FeeResult), Error>` - A tuple containing a map of token infos and the associated fee result. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identities_token_infos_with_costs( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(BTreeMap<[u8; 32], Option>, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identities_token_infos_operations( + token_id, + identity_ids, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to fetch the identity's token infos from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the infos for. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding infos, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identities_token_infos_operations( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identities_token_infos + { + 0 => self.fetch_identities_token_infos_operations_v0( + token_id, + identity_ids, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identities_token_infos_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/v0/mod.rs new file mode 100644 index 0000000000..e892dcd7aa --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identities_token_infos/v0/mod.rs @@ -0,0 +1,66 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::Element::Item; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_identities_token_infos_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + self.fetch_identities_token_infos_operations_v0( + token_id, + identity_ids, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_identities_token_infos_operations_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let path_query = Self::token_infos_for_identity_ids_query(token_id, identity_ids); + + self.grove_get_raw_path_query_with_optional( + &path_query, + false, + transaction, + drive_operations, + &platform_version.drive, + )? + .into_iter() + .map(|(_, key, element)| { + let identity_id: [u8; 32] = key.try_into().map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "identity id not 32 bytes".to_string(), + )) + })?; + match element { + Some(Item(value, ..)) => Ok(( + identity_id, + Some(IdentityTokenInfo::deserialize_from_bytes(&value)?), + )), + None => Ok((identity_id, None)), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "token tree for infos should contain only items".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/mod.rs new file mode 100644 index 0000000000..3fa1a5dad0 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/mod.rs @@ -0,0 +1,134 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the Identity's token info from the backing store. + /// Passing `apply = false` will return estimated costs (0 or Some(0) in place of actual values). + /// + /// # Arguments + /// + /// * `token_id` - The ID of the token. + /// * `identity_id` - The ID of the Identity whose token info is to be fetched. + /// * `apply` - Whether to actually fetch from state (true) or estimate costs (false). + /// * `transaction` - The current transaction. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - The token info of the Identity if successful, or an error. + pub fn fetch_identity_token_info( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_info + { + 0 => self.fetch_identity_token_info_v0( + token_id, + identity_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_info".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the Identity's token info with costs (if `apply = true`) and returns associated fee result. + pub fn fetch_identity_token_info_with_costs( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Option, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identity_token_info_operations( + token_id, + identity_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the operations to get Identity's token info from the backing store. + /// If `apply` is false, the operations are stateless and only used for cost estimation. + /// + /// # Arguments + /// + /// * `token_id` - The ID of the token. + /// * `identity_id` - The ID of the Identity whose token info is to be fetched. + /// * `apply` - Whether to fetch actual stateful data (true) or just estimate costs (false). + /// * `transaction` - The current transaction. + /// * `drive_operations` - The drive operations vector to populate. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - The token info of the Identity if successful, or an error. + pub fn fetch_identity_token_info_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_info + { + 0 => self.fetch_identity_token_info_operations_v0( + token_id, + identity_id, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_info_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/v0/mod.rs new file mode 100644 index 0000000000..e923a435d9 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_info/v0/mod.rs @@ -0,0 +1,73 @@ +use crate::drive::tokens::paths::token_identity_infos_path; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::Element::Item; +use grovedb::{TransactionArg, TreeType}; + +impl Drive { + pub(super) fn fetch_identity_token_info_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.fetch_identity_token_info_operations_v0( + token_id, + identity_id, + true, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_identity_token_info_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let direct_query_type = if apply { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let info_path = token_identity_infos_path(&token_id); + + match self.grove_get_raw_optional( + (&info_path).into(), + identity_id.as_slice(), + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + ) { + Ok(Some(Item(info, _))) => Ok(Some(IdentityTokenInfo::deserialize_from_bytes( + info.as_slice(), + )?)), + + Ok(None) | Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) => Ok(None), + + Ok(Some(_)) => Err(Error::Drive(DriveError::CorruptedElementType( + "identity token info was present but was not an item", + ))), + + Err(e) => Err(e), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/mod.rs new file mode 100644 index 0000000000..a8335427f8 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/mod.rs @@ -0,0 +1,151 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + /// Fetches the token infos of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose infos are to be fetched. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding infos, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identity_token_infos( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_infos + { + 0 => self.fetch_identity_token_infos_v0( + token_ids, + identity_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token infos with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to fetch the infos for. + /// * `identity_id` - The identity's ID whose infos are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result<((BTreeMap<[u8; 32], Option>), FeeResult), Error>` - A tuple containing a map of token infos and the associated fee result. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identity_token_infos_with_costs( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(BTreeMap<[u8; 32], Option>, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_identity_token_infos_operations( + token_ids, + identity_id, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to fetch the identity's token infos from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the infos for. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding infos, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_identity_token_infos_operations( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .token + .fetch + .identity_token_infos + { + 0 => self.fetch_identity_token_infos_operations_v0( + token_ids, + identity_id, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_identity_token_infos_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs new file mode 100644 index 0000000000..6779f88038 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs @@ -0,0 +1,87 @@ +use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_IDENTITY_INFO_KEY}; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::Element::Item; +use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_identity_token_infos_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + self.fetch_identity_token_infos_operations_v0( + token_ids, + identity_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_identity_token_infos_operations_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let tokens_root = tokens_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![vec![TOKEN_IDENTITY_INFO_KEY], identity_id.to_vec()]); + + let path_query = PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ); + + self.grove_get_raw_path_query_with_optional( + &path_query, + false, + transaction, + drive_operations, + &platform_version.drive, + )? + .into_iter() + .map(|(path, _, element)| { + let token_id: [u8; 32] = path + .get(1) + .ok_or(Error::Drive(DriveError::CorruptedDriveState( + "returned path item should always have a second part at index 1".to_string(), + )))? + .clone() + .try_into() + .map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "token id not 32 bytes".to_string(), + )) + })?; + match element { + Some(Item(value, ..)) => Ok(( + token_id, + Some(IdentityTokenInfo::deserialize_from_bytes(&value)?), + )), + None => Ok((token_id, None)), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "token tree for infos should contain only items".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/mod.rs b/packages/rs-drive/src/drive/tokens/info/mod.rs new file mode 100644 index 0000000000..f446d8668d --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/mod.rs @@ -0,0 +1,12 @@ +#[cfg(feature = "server")] +mod fetch_identities_token_infos; +#[cfg(feature = "server")] +mod fetch_identity_token_infos; +#[cfg(feature = "server")] +mod prove_identities_token_infos; +#[cfg(feature = "server")] +mod prove_identity_token_infos; +mod queries; + +#[cfg(feature = "server")] +mod fetch_identity_token_info; diff --git a/packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/mod.rs b/packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/mod.rs new file mode 100644 index 0000000000..918eeafe94 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/mod.rs @@ -0,0 +1,149 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Proves the token infos of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose infos are to be proveed. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identities_token_infos( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identity_token_infos + { + 0 => self.prove_identities_token_infos_v0( + token_id, + identity_ids, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identity_token_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves the identity's token infos with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to prove the infos for. + /// * `identity_id` - The identity's ID whose infos are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identities_token_infos_with_costs( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Vec, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.prove_identities_token_infos_operations( + token_id, + identity_ids, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to prove the identity's token infos from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the infos for. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identities_token_infos_operations( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identity_token_infos + { + 0 => self.prove_identities_token_infos_operations_v0( + token_id, + identity_ids, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identities_token_infos_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/v0/mod.rs new file mode 100644 index 0000000000..d74ae92a50 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/prove_identities_token_infos/v0/mod.rs @@ -0,0 +1,353 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + pub(super) fn prove_identities_token_infos_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_identities_token_infos_operations_v0( + token_id, + identity_ids, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_identities_token_infos_operations_v0( + &self, + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = Self::token_infos_for_identity_ids_query(token_id, identity_ids); + + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::v1::DataContractV1; + use dpp::identity::Identity; + use std::collections::BTreeMap; + + use dpp::identity::accessors::IdentityGettersV0; + use dpp::prelude::DataContract; + use dpp::tokens::info::IdentityTokenInfo; + use dpp::version::PlatformVersion; + + #[test] + fn should_prove_a_single_identity_token_info() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + drive + .token_freeze( + token_id, + identity.id(), + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token"); + let proof = drive + .prove_identities_token_infos_v0( + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_info: BTreeMap<[u8; 32], Option> = + Drive::verify_token_infos_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!( + proved_identity_info, + BTreeMap::from([( + identity_id, + Some(IdentityTokenInfo::new(true, platform_version).expect("expected token info")) + )]) + ); + } + + #[test] + fn should_prove_a_single_identity_token_info_does_not_exist() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + let proof = drive + .prove_identities_token_infos_v0( + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_info: BTreeMap<[u8; 32], Option> = + Drive::verify_token_infos_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!(proved_identity_info, BTreeMap::from([(identity_id, None)])); + } + + #[test] + fn should_prove_multiple_identity_single_token_infos() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity_1 = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_1_id = identity_1.id().to_buffer(); + + let identity_2 = Identity::random_identity(3, Some(15), platform_version) + .expect("expected a platform identity"); + + let identity_2_id = identity_2.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + let token_id = contract.token_id(0).expect("expected token at position 0"); + drive + .add_new_identity( + identity_1.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .add_new_identity( + identity_2.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + drive + .token_freeze( + token_id, + identity_1.id(), + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token"); + + let proof = drive + .prove_identities_token_infos_v0( + token_id.to_buffer(), + &vec![identity_1.id().to_buffer(), identity_2.id().to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving an identity"); + + let proved_identity_info: BTreeMap<[u8; 32], Option> = + Drive::verify_token_infos_for_identity_ids( + proof.as_slice(), + token_id.to_buffer(), + &vec![identity_1.id().to_buffer(), identity_2.id().to_buffer()], + false, + platform_version, + ) + .expect("expect that this be verified") + .1; + + assert_eq!( + proved_identity_info, + BTreeMap::from([ + ( + identity_1_id, + Some( + IdentityTokenInfo::new(true, platform_version) + .expect("expected token info") + ) + ), + (identity_2_id, None) + ]) + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/mod.rs b/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/mod.rs new file mode 100644 index 0000000000..a43d6083ac --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/mod.rs @@ -0,0 +1,149 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the token infos of an identity from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose infos are to be proveed. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identity_token_infos( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identity_token_infos + { + 0 => self.prove_identity_token_infos_v0( + token_ids, + identity_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identity_token_infos".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token infos with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to prove the infos for. + /// * `identity_id` - The identity's ID whose infos are being queried. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identity_token_infos_with_costs( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Vec, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.prove_identity_token_infos_operations( + token_ids, + identity_id, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to prove the identity's token infos from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the infos for. + /// * `identity_id` - The ID of the identity whose token infos are being queried. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_identity_token_infos_operations( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .identity_token_infos + { + 0 => self.prove_identity_token_infos_operations_v0( + token_ids, + identity_id, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_identity_token_infos_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs new file mode 100644 index 0000000000..a0e4e71ac9 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs @@ -0,0 +1,55 @@ +use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_IDENTITY_INFO_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::PlatformVersion; +use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; + +impl Drive { + pub(super) fn prove_identity_token_infos_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_identity_token_infos_operations_v0( + token_ids, + identity_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_identity_token_infos_operations_v0( + &self, + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let tokens_root = tokens_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![vec![TOKEN_IDENTITY_INFO_KEY], identity_id.to_vec()]); + + let path_query = PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ); + + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/queries.rs b/packages/rs-drive/src/drive/tokens/info/queries.rs new file mode 100644 index 0000000000..3b2303932d --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/info/queries.rs @@ -0,0 +1,72 @@ +use crate::drive::tokens::paths::token_identity_infos_path_vec; +use crate::drive::Drive; +use crate::query::{Query, QueryItem}; +use grovedb::{PathQuery, SizedQuery}; +use std::ops::RangeFull; + +impl Drive { + /// The query for proving the identities info of a token from an identity id. + pub fn token_info_for_identity_id_query( + token_id: [u8; 32], + identity_id: [u8; 32], + ) -> PathQuery { + let info_path = token_identity_infos_path_vec(token_id); + PathQuery::new_single_key(info_path, identity_id.to_vec()) + } + + /// The query getting a token info for many identities + pub fn token_infos_for_identity_ids_query( + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + ) -> PathQuery { + let info_path = token_identity_infos_path_vec(token_id); + let mut query = Query::new(); + query.insert_keys(identity_ids.iter().map(|key| key.to_vec()).collect()); + PathQuery { + path: info_path, + query: SizedQuery { + query, + limit: Some(identity_ids.len() as u16), + offset: None, + }, + } + } + + /// The query getting token infos for identities in a range + pub fn token_infos_for_range_query( + token_id: [u8; 32], + start_at: Option<([u8; 32], bool)>, + ascending: bool, + limit: u16, + ) -> PathQuery { + let info_path = token_identity_infos_path_vec(token_id); + let mut query = Query::new_with_direction(ascending); + if ascending { + if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeFrom(start_at.to_vec()..)) + } else { + query.insert_item(QueryItem::RangeAfter(start_at.to_vec()..)) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + } else if let Some((start_at, start_at_included)) = start_at { + if start_at_included { + query.insert_item(QueryItem::RangeToInclusive(..=start_at.to_vec())) + } else { + query.insert_item(QueryItem::RangeTo(..start_at.to_vec())) + } + } else { + query.insert_item(QueryItem::RangeFull(RangeFull)) + } + PathQuery { + path: info_path, + query: SizedQuery { + query, + limit: Some(limit), + offset: None, + }, + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/mint/mod.rs b/packages/rs-drive/src/drive/tokens/mint/mod.rs new file mode 100644 index 0000000000..ddcab0a856 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/mint/mod.rs @@ -0,0 +1,106 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Mints (issues) new tokens by increasing the total supply and adding them to an identity's balance. + pub fn token_mint( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + issuance_amount: u64, + allow_first_mint: bool, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.token.update.mint { + 0 => self.token_mint_v0( + token_id, + identity_id, + issuance_amount, + allow_first_mint, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_mint".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations to mint tokens without calculating fees and optionally applying. + pub fn token_mint_add_to_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + issuance_amount: u64, + allow_first_mint: bool, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.token.update.mint { + 0 => self.token_mint_add_to_operations_v0( + token_id, + identity_id, + issuance_amount, + allow_first_mint, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_mint_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Gathers the operations needed to mint tokens. + pub fn token_mint_operations( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + issuance_amount: u64, + allow_first_mint: bool, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.update.mint { + 0 => self.token_mint_operations_v0( + token_id, + identity_id, + issuance_amount, + allow_first_mint, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_mint_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/mint/v0/mod.rs b/packages/rs-drive/src/drive/tokens/mint/v0/mod.rs new file mode 100644 index 0000000000..f0d737455a --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/mint/v0/mod.rs @@ -0,0 +1,115 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn token_mint_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + issuance_amount: u64, + allow_first_mint: bool, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.token_mint_add_to_operations_v0( + token_id, + identity_id, + issuance_amount, + allow_first_mint, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn token_mint_add_to_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + issuance_amount: u64, + allow_first_mint: bool, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.token_mint_operations_v0( + token_id, + identity_id, + issuance_amount, + allow_first_mint, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn token_mint_operations_v0( + &self, + token_id: [u8; 32], + identity_id: [u8; 32], + issuance_amount: u64, + allow_first_mint: bool, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + // Update identity balance + drive_operations.extend(self.add_to_identity_token_balance_operations( + token_id, + identity_id, + issuance_amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + + drive_operations.extend(self.add_to_token_total_supply_operations( + token_id, + issuance_amount, + allow_first_mint, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/mod.rs b/packages/rs-drive/src/drive/tokens/mod.rs new file mode 100644 index 0000000000..c1f8f4fa90 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/mod.rs @@ -0,0 +1,54 @@ +/// Handles operations related to adding transaction history. +#[cfg(feature = "server")] +mod add_transaction_history_operations; + +/// Defines logic for applying status updates within the system. +#[cfg(feature = "server")] +pub mod apply_status; + +/// Manages operations related to balance handling. +#[cfg(any(feature = "server", feature = "verify"))] +pub mod balance; + +/// Implements functionality for burning tokens. +#[cfg(feature = "server")] +pub mod burn; + +/// Computes estimated costs for various operations. +#[cfg(feature = "server")] +pub mod estimated_costs; + +/// Manages freezing operations in the system. +#[cfg(feature = "server")] +pub mod freeze; + +/// Identity token info module, like if someone is frozen +#[cfg(any(feature = "server", feature = "verify"))] +pub mod info; + +/// Implements minting operations for creating new tokens. +#[cfg(feature = "server")] +pub mod mint; + +/// Manages system-level operations and utilities. +#[cfg(feature = "server")] +pub mod system; + +/// Handles transfer operations, including token movement. +#[cfg(feature = "server")] +pub mod transfer; + +/// Manages unfreezing operations within the system. +#[cfg(feature = "server")] +pub mod unfreeze; + +/// Calculates the total token balance across all accounts. +#[cfg(feature = "server")] +pub mod calculate_total_tokens_balance; + +/// Token status module, like if the token is paused +#[cfg(feature = "server")] +pub mod status; + +/// Token paths +pub mod paths; diff --git a/packages/rs-drive/src/drive/tokens/paths.rs b/packages/rs-drive/src/drive/tokens/paths.rs new file mode 100644 index 0000000000..ce5b8ef89c --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/paths.rs @@ -0,0 +1,105 @@ +use crate::drive::RootTree; + +/// Key for accessing token status information. +pub const TOKEN_STATUS_INFO_KEY: u8 = 96; +/// Key for accessing token identity information tree. +pub const TOKEN_IDENTITY_INFO_KEY: u8 = 160; +/// Key for accessing token balances tree. +pub const TOKEN_BALANCES_KEY: u8 = 128; + +/// The path for the balances tree + +pub fn tokens_root_path() -> [&'static [u8]; 1] { + [Into::<&[u8; 1]>::into(RootTree::Tokens)] +} + +/// The path for the balances tree + +pub fn tokens_root_path_vec() -> Vec> { + vec![Into::<&[u8; 1]>::into(RootTree::Tokens).to_vec()] +} + +/// The root path of token balances tree, this refers to a big sum tree + +pub fn token_balances_root_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::Tokens), + &[TOKEN_BALANCES_KEY], + ] +} + +/// The root path of token balances tree, this refers to a big sum tree + +pub fn token_balances_root_path_vec() -> Vec> { + vec![vec![RootTree::Tokens as u8], vec![TOKEN_BALANCES_KEY]] +} + +/// Returns the root path for token identity information as a fixed-size array of byte slices. + +pub fn token_identity_infos_root_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::Tokens), + &[TOKEN_IDENTITY_INFO_KEY], + ] +} + +/// Returns the root path for token identity information as a vector of byte vectors. + +pub fn token_identity_infos_root_path_vec() -> Vec> { + vec![vec![RootTree::Tokens as u8], vec![TOKEN_IDENTITY_INFO_KEY]] +} + +/// Returns the root path for token statuses as a fixed-size array of byte slices. + +pub fn token_statuses_root_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::Tokens), + &[TOKEN_STATUS_INFO_KEY], + ] +} + +/// Returns the root path for token statuses as a vector of byte vectors. + +pub fn token_statuses_root_path_vec() -> Vec> { + vec![vec![RootTree::Tokens as u8], vec![TOKEN_STATUS_INFO_KEY]] +} + +/// The path for the token balances tree + +pub fn token_balances_path(token_id: &[u8; 32]) -> [&[u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::Tokens), + &[TOKEN_BALANCES_KEY], + token_id, + ] +} + +/// The path for the token balances tree + +pub fn token_balances_path_vec(token_id: [u8; 32]) -> Vec> { + vec![ + vec![RootTree::Tokens as u8], + vec![TOKEN_BALANCES_KEY], + token_id.to_vec(), + ] +} + +/// The path for the token info tree + +pub fn token_identity_infos_path(token_id: &[u8; 32]) -> [&[u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::Tokens), + &[TOKEN_IDENTITY_INFO_KEY], + token_id, + ] +} + +/// The path for the token info tree + +pub fn token_identity_infos_path_vec(token_id: [u8; 32]) -> Vec> { + vec![ + vec![RootTree::Tokens as u8], + vec![TOKEN_IDENTITY_INFO_KEY], + token_id.to_vec(), + ] +} diff --git a/packages/rs-drive/src/drive/tokens/status/fetch_token_status/mod.rs b/packages/rs-drive/src/drive/tokens/status/fetch_token_status/mod.rs new file mode 100644 index 0000000000..f8b590441b --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/fetch_token_status/mod.rs @@ -0,0 +1,110 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::tokens::status::TokenStatus; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Fetches the Token status from the backing store. + /// Passing `apply = false` will return estimated costs (0 or Some(0) in place of actual values). + /// + /// # Arguments + /// + /// * `token_id` - The ID of the token. + /// * `apply` - Whether to actually fetch from state (true) or estimate costs (false). + /// * `transaction` - The current transaction. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - The token info of the Identity if successful, or an error. + pub fn fetch_token_status( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.fetch.token_status { + 0 => self.fetch_token_status_v0(token_id, transaction, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_status".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the Token status with costs (if `apply = true`) and returns associated fee result. + pub fn fetch_token_status_with_costs( + &self, + token_id: [u8; 32], + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Option, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_token_status_operations( + token_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the operations to get Token's status from the backing store. + /// If `apply` is false, the operations are stateless and only used for cost estimation. + /// + /// # Arguments + /// + /// * `token_id` - The ID of the token. + /// * `apply` - Whether to fetch actual stateful data (true) or just estimate costs (false). + /// * `transaction` - The current transaction. + /// * `drive_operations` - The drive operations vector to populate. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - The token info of the Identity if successful, or an error. + pub fn fetch_token_status_operations( + &self, + token_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.fetch.token_status { + 0 => self.fetch_token_status_operations_v0( + token_id, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_status_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/status/fetch_token_status/v0/mod.rs b/packages/rs-drive/src/drive/tokens/status/fetch_token_status/v0/mod.rs new file mode 100644 index 0000000000..db71c1cd7e --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/fetch_token_status/v0/mod.rs @@ -0,0 +1,70 @@ +use crate::drive::tokens::paths::token_statuses_root_path; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::status::TokenStatus; +use dpp::version::PlatformVersion; +use grovedb::Element::Item; +use grovedb::{TransactionArg, TreeType}; + +impl Drive { + pub(super) fn fetch_token_status_v0( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.fetch_token_status_operations_v0( + token_id, + true, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_token_status_operations_v0( + &self, + token_id: [u8; 32], + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let direct_query_type = if apply { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let token_statuses_root_path = token_statuses_root_path(); + + match self.grove_get_raw_optional( + (&token_statuses_root_path).into(), + &token_id, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + ) { + Ok(Some(Item(info, _))) => { + Ok(Some(TokenStatus::deserialize_from_bytes(info.as_slice())?)) + } + + Ok(None) | Err(Error::GroveDB(grovedb::Error::PathKeyNotFound(_))) => Ok(None), + + Ok(Some(_)) => Err(Error::Drive(DriveError::CorruptedElementType( + "token status was present but was not an item", + ))), + + Err(e) => Err(e), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/mod.rs b/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/mod.rs new file mode 100644 index 0000000000..9f81e5ab2e --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/mod.rs @@ -0,0 +1,126 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::tokens::status::TokenStatus; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Drive { + /// Fetches token statuses from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose infos are to be fetched. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding infos, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_token_statuses( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version.drive.methods.token.fetch.token_statuses { + 0 => self.fetch_token_statuses_v0(token_ids, transaction, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_statuses".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Fetches the identity's token infos with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to fetch the infos for. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result<((BTreeMap<[u8; 32], Option>), FeeResult), Error>` - A tuple containing a map of token infos and the associated fee result. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_token_statuses_with_costs( + &self, + token_ids: &[[u8; 32]], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(BTreeMap<[u8; 32], Option>, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.fetch_token_statuses_operations( + token_ids, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to fetch the identity's token infos from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the infos for. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result>, Error>` - A map of token IDs to their corresponding statuses. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn fetch_token_statuses_operations( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version.drive.methods.token.fetch.token_statuses { + 0 => self.fetch_token_statuses_operations_v0( + token_ids, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_statuses_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs b/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs new file mode 100644 index 0000000000..486ebde128 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs @@ -0,0 +1,76 @@ +use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_STATUS_INFO_KEY}; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::status::TokenStatus; +use dpp::version::PlatformVersion; +use grovedb::Element::Item; +use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use std::collections::BTreeMap; + +impl Drive { + pub(super) fn fetch_token_statuses_v0( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + self.fetch_token_statuses_operations_v0( + token_ids, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn fetch_token_statuses_operations_v0( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let tokens_root = tokens_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![vec![TOKEN_STATUS_INFO_KEY]]); + + let path_query = PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ); + + self.grove_get_raw_path_query_with_optional( + &path_query, + false, + transaction, + drive_operations, + &platform_version.drive, + )? + .into_iter() + .map(|(_, key, element)| { + let token_id: [u8; 32] = key.try_into().map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "token id not 32 bytes".to_string(), + )) + })?; + match element { + Some(Item(value, ..)) => { + Ok((token_id, Some(TokenStatus::deserialize_from_bytes(&value)?))) + } + None => Ok((token_id, None)), + _ => Err(Error::Drive(DriveError::CorruptedDriveState( + "token tree for statuses should contain only items".to_string(), + ))), + } + }) + .collect() + } +} diff --git a/packages/rs-drive/src/drive/tokens/status/mod.rs b/packages/rs-drive/src/drive/tokens/status/mod.rs new file mode 100644 index 0000000000..57d88f594e --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/mod.rs @@ -0,0 +1,7 @@ +#[cfg(feature = "server")] +mod fetch_token_statuses; + +#[cfg(feature = "server")] +mod fetch_token_status; +#[cfg(feature = "server")] +mod prove_token_statuses; diff --git a/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/mod.rs b/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/mod.rs new file mode 100644 index 0000000000..29e31ef594 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/mod.rs @@ -0,0 +1,124 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Proves the token statuses from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs whose statuses are to be proved. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The version of the platform to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_token_statuses( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.prove.token_statuses { + 0 => self.prove_token_statuses_v0(token_ids, transaction, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_token_statuses".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves the token statuses with associated costs. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to prove the infos for. + /// * `block_info` - Information about the current block for fee calculation. + /// * `transaction` - The current transaction context. + /// * `platform_version` - The platform version to use. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_token_statuses_with_costs( + &self, + token_ids: &[[u8; 32]], + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Vec, FeeResult), Error> { + let mut drive_operations: Vec = vec![]; + let value = self.prove_token_statuses_operations( + token_ids, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok((value, fees)) + } + + /// Creates the low-level operations needed to prove the Token statuses from the backing store. + /// + /// # Arguments + /// + /// * `token_ids` - A list of token IDs to query the statuses for. + /// * `transaction` - The current transaction context. + /// * `drive_operations` - A vector to store the created low-level drive operations. + /// * `platform_version` - The platform version to use for compatibility checks. + /// + /// # Returns + /// + /// * `Result, Error>` - A grovedb proof, or an error. + /// + /// # Errors + /// + /// * `DriveError::UnknownVersionMismatch` - If the platform version does not support the requested operation. + pub fn prove_token_statuses_operations( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.prove.token_statuses { + 0 => self.prove_token_statuses_operations_v0( + token_ids, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_token_statuses_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs b/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs new file mode 100644 index 0000000000..baae7936be --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs @@ -0,0 +1,52 @@ +use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_IDENTITY_INFO_KEY}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::PlatformVersion; +use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; + +impl Drive { + pub(super) fn prove_token_statuses_v0( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_token_statuses_operations_v0( + token_ids, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_token_statuses_operations_v0( + &self, + token_ids: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let tokens_root = tokens_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![vec![TOKEN_IDENTITY_INFO_KEY]]); + + let path_query = PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ); + + self.grove_get_proved_path_query( + &path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/mod.rs b/packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/mod.rs new file mode 100644 index 0000000000..4daa069ec8 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/mod.rs @@ -0,0 +1,119 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Adds to the token's total supply + pub fn add_to_token_total_supply( + &self, + token_id: [u8; 32], + amount: u64, + allow_first_mint: bool, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .token + .update + .add_to_token_total_supply + { + 0 => self.add_to_token_total_supply_v0( + token_id, + amount, + allow_first_mint, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_to_token_total_supply".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations of adding to the token total supply + pub fn add_to_token_total_supply_add_to_operations( + &self, + token_id: [u8; 32], + amount: u64, + allow_first_mint: bool, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive + .methods + .token + .update + .add_to_token_total_supply + { + 0 => self.add_to_token_total_supply_add_to_operations_v0( + token_id, + amount, + allow_first_mint, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_to_token_total_supply_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to add to the token total supply + pub fn add_to_token_total_supply_operations( + &self, + token_id: [u8; 32], + amount: u64, + allow_first_mint: bool, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .update + .add_to_token_total_supply + { + 0 => self.add_to_token_total_supply_operations_v0( + token_id, + amount, + allow_first_mint, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_to_token_total_supply_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/v0/mod.rs new file mode 100644 index 0000000000..686591211a --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/add_to_token_total_supply/v0/mod.rs @@ -0,0 +1,148 @@ +use crate::drive::balances::{total_tokens_root_supply_path, total_tokens_root_supply_path_vec}; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::GroveOperation; +use crate::util::grove_operations::DirectQueryType; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp}; +use grovedb::Element::SumItem; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn add_to_token_total_supply_v0( + &self, + token_id: [u8; 32], + amount: u64, + allow_first_mint: bool, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.add_to_token_total_supply_add_to_operations_v0( + token_id, + amount, + apply, + allow_first_mint, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn add_to_token_total_supply_add_to_operations_v0( + &self, + token_id: [u8; 32], + amount: u64, + allow_first_mint: bool, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.add_to_token_total_supply_operations_v0( + token_id, + amount, + allow_first_mint, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn add_to_token_total_supply_operations_v0( + &self, + token_id: [u8; 32], + amount: u64, + allow_first_mint: bool, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + // If we only estimate, add estimation costs + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + // Add your estimation logic similar to add_to_system_credits_operations_v0 + // For example: + Self::add_estimation_costs_for_token_total_supply( + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let path_holding_total_token_supply = total_tokens_root_supply_path(); + let path_holding_total_token_supply_vec = total_tokens_root_supply_path_vec(); + let total_token_supply_in_platform = self.grove_get_raw_value_u64_from_encoded_var_vec( + (&path_holding_total_token_supply).into(), + &token_id, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if let Some(total_token_supply_in_platform) = total_token_supply_in_platform { + let new_total = (total_token_supply_in_platform as i64) + .checked_add(amount as i64) + .ok_or(Error::Drive(DriveError::CriticalCorruptedState( + "trying to add an amount that would underflow total supply", + )))?; + let replace_op = QualifiedGroveDbOp::replace_op( + path_holding_total_token_supply_vec, + token_id.to_vec(), + SumItem(new_total, None), + ); + drive_operations.push(GroveOperation(replace_op)); + } else if allow_first_mint { + if amount > i64::MAX as u64 { + return Err(Error::Drive(DriveError::CriticalCorruptedState( + "amount is over max allowed in Sum Item (i64::Max)", + ))); + } + let insert_op = QualifiedGroveDbOp::insert_only_op( + path_holding_total_token_supply_vec, + token_id.to_vec(), + SumItem(amount as i64, None), + ); + drive_operations.push(GroveOperation(insert_op)); + } else { + return Err(Error::Drive(DriveError::CriticalCorruptedState( + "Total supply for token not found in Platform", + ))); + } + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/create_token_trees/mod.rs b/packages/rs-drive/src/drive/tokens/system/create_token_trees/mod.rs new file mode 100644 index 0000000000..49656bb930 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/create_token_trees/mod.rs @@ -0,0 +1,124 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; + +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Adds an identity by inserting a new identity subtree structure to the `Identities` subtree. + pub fn create_token_trees( + &self, + token_id: [u8; 32], + start_as_paused: bool, + allow_already_exists: bool, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .token + .update + .create_token_trees + { + 0 => self.create_token_trees_v0( + token_id, + start_as_paused, + allow_already_exists, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "create_token_trees".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds identity creation operations to drive operations + pub fn create_token_trees_add_to_operations( + &self, + token_id: [u8; 32], + start_as_paused: bool, + allow_already_exists: bool, + apply: bool, + previous_batch_operations: &mut Option<&mut Vec>, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive + .methods + .token + .update + .create_token_trees + { + 0 => self.create_token_trees_add_to_operations_v0( + token_id, + start_as_paused, + allow_already_exists, + apply, + previous_batch_operations, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "create_token_trees_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to create an identity + pub fn create_token_trees_operations( + &self, + token_id: [u8; 32], + start_as_paused: bool, + allow_already_exists: bool, + previous_batch_operations: &mut Option<&mut Vec>, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .update + .create_token_trees + { + 0 => self.create_token_trees_operations_v0( + token_id, + start_as_paused, + allow_already_exists, + previous_batch_operations, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "create_token_trees_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/create_token_trees/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/create_token_trees/v0/mod.rs new file mode 100644 index 0000000000..71224f1328 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/create_token_trees/v0/mod.rs @@ -0,0 +1,220 @@ +use crate::drive::balances::total_tokens_root_supply_path; +use crate::drive::tokens::paths::{ + token_balances_root_path, token_identity_infos_root_path, token_statuses_root_path, +}; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::{BatchInsertApplyType, BatchInsertTreeApplyType, QueryTarget}; +use crate::util::object_size_info::PathKeyElementInfo; +use crate::util::object_size_info::PathKeyInfo::PathFixedSizeKeyRef; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::serialization::PlatformSerializable; +use dpp::tokens::status::TokenStatus; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +impl Drive { + /// Creates a new token root subtree at `TokenBalances` keyed by `token_id`. + /// This function applies the operations directly, calculates fees, and returns the fee result. + pub(super) fn create_token_trees_v0( + &self, + token_id: [u8; 32], + start_as_paused: bool, + allow_already_exists: bool, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations: Vec = vec![]; + + // Add operations to create the token root tree + self.create_token_trees_add_to_operations_v0( + token_id, + start_as_paused, + allow_already_exists, + apply, + &mut None, + transaction, + &mut drive_operations, + platform_version, + )?; + + // If applying, calculate fees + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + /// Adds the token root creation operations to the provided `drive_operations` vector without + /// calculating or returning fees. If `apply` is false, it will only estimate costs. + pub(super) fn create_token_trees_add_to_operations_v0( + &self, + token_id: [u8; 32], + start_as_paused: bool, + allow_already_exists: bool, + apply: bool, + previous_batch_operations: &mut Option<&mut Vec>, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = if apply { + None::> + } else { + Some(HashMap::new()) + }; + + // Get the operations required to create the token tree + let batch_operations = self.create_token_trees_operations_v0( + token_id, + start_as_paused, + allow_already_exists, + previous_batch_operations, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + // Apply or estimate the operations + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + /// Gathers the operations needed to create the token root subtree. If `apply` is false, it + /// populates `estimated_costs_only_with_layer_info` instead of applying. + pub(super) fn create_token_trees_operations_v0( + &self, + token_id: [u8; 32], + start_as_paused: bool, + allow_already_exists: bool, + previous_batch_operations: &mut Option<&mut Vec>, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut batch_operations: Vec = vec![]; + + let non_sum_tree_apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertTreeApplyType::StatefulBatchInsertTree + } else { + BatchInsertTreeApplyType::StatelessBatchInsertTree { + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, + flags_len: 0, + } + }; + + let item_apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertApplyType::StatefulBatchInsert + } else { + BatchInsertApplyType::StatelessBatchInsert { + in_tree_type: TreeType::NormalTree, + target: QueryTarget::QueryTargetValue(8), + } + }; + + let token_balance_tree_apply_type = if estimated_costs_only_with_layer_info.is_none() { + BatchInsertTreeApplyType::StatefulBatchInsertTree + } else { + BatchInsertTreeApplyType::StatelessBatchInsertTree { + in_tree_type: TreeType::BigSumTree, + tree_type: TreeType::SumTree, + flags_len: 0, + } + }; + + // Insert an empty tree for this token if it doesn't exist + let inserted = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKeyRef::<2>((token_balances_root_path(), token_id.as_slice())), + TreeType::SumTree, + None, + token_balance_tree_apply_type, + transaction, + previous_batch_operations, + &mut batch_operations, + &platform_version.drive, + )?; + + if !inserted && !allow_already_exists { + // The token root already exists. Depending on your logic, this might be allowed or should be treated as an error. + return Err(Error::Drive(DriveError::CorruptedDriveState( + "token balance root tree already exists".to_string(), + ))); + } + + let inserted = self.batch_insert_empty_tree_if_not_exists( + PathFixedSizeKeyRef::<2>((token_identity_infos_root_path(), token_id.as_slice())), + TreeType::NormalTree, + None, + non_sum_tree_apply_type, + transaction, + &mut None, + &mut batch_operations, + &platform_version.drive, + )?; + + if !inserted && !allow_already_exists { + // The token root already exists. Depending on your logic, this might be allowed or should be treated as an error. + return Err(Error::Drive(DriveError::CorruptedDriveState( + "token balance tree already exists".to_string(), + ))); + } + + let starting_status = TokenStatus::new(start_as_paused, platform_version)?; + let token_status_bytes = starting_status.serialize_consume_to_bytes()?; + + let inserted = self.batch_insert_if_not_exists( + PathKeyElementInfo::PathFixedSizeKeyRefElement::<2>(( + token_statuses_root_path(), + token_id.as_slice(), + Element::Item(token_status_bytes, None), + )), + item_apply_type, + transaction, + &mut batch_operations, + &platform_version.drive, + )?; + + if !inserted && !allow_already_exists { + // The token root already exists. Depending on your logic, this might be allowed or should be treated as an error. + return Err(Error::Drive(DriveError::CorruptedDriveState( + "token info tree already exists".to_string(), + ))); + } + + self.batch_insert_sum_item_if_not_exists( + PathKeyElementInfo::PathFixedSizeKeyRefElement::<2>(( + total_tokens_root_supply_path(), + token_id.as_slice(), + Element::SumItem(0, None), + )), + !allow_already_exists, + item_apply_type, + transaction, + &mut batch_operations, + &platform_version.drive, + )?; + + Ok(batch_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/mod.rs b/packages/rs-drive/src/drive/tokens/system/mod.rs new file mode 100644 index 0000000000..8d0f456d61 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/mod.rs @@ -0,0 +1,3 @@ +mod add_to_token_total_supply; +mod create_token_trees; +mod remove_from_token_total_supply; diff --git a/packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/mod.rs b/packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/mod.rs new file mode 100644 index 0000000000..4ede94b632 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/mod.rs @@ -0,0 +1,112 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Removes from the token's total supply + pub fn remove_from_token_total_supply( + &self, + token_id: [u8; 32], + amount: u64, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .token + .update + .remove_from_token_total_supply + { + 0 => self.remove_from_token_total_supply_v0( + token_id, + amount, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "remove_from_token_total_supply".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations of removing from the token total supply + pub fn remove_from_token_total_supply_add_to_operations( + &self, + token_id: [u8; 32], + amount: u64, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive + .methods + .token + .update + .remove_from_token_total_supply + { + 0 => self.remove_from_token_total_supply_add_to_operations_v0( + token_id, + amount, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "remove_from_token_total_supply_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// The operations needed to remove from the token total supply + pub fn remove_from_token_total_supply_operations( + &self, + token_id: [u8; 32], + amount: u64, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .update + .remove_from_token_total_supply + { + 0 => self.remove_from_token_total_supply_operations_v0( + token_id, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "remove_from_token_total_supply_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/v0/mod.rs new file mode 100644 index 0000000000..1bdbe38ebb --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/remove_from_token_total_supply/v0/mod.rs @@ -0,0 +1,128 @@ +use crate::drive::balances::{total_tokens_root_supply_path, total_tokens_root_supply_path_vec}; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::GroveOperation; +use crate::util::grove_operations::DirectQueryType; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::batch::QualifiedGroveDbOp; +use grovedb::Element::SumItem; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn remove_from_token_total_supply_v0( + &self, + token_id: [u8; 32], + amount: u64, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.remove_from_token_total_supply_add_to_operations_v0( + token_id, + amount, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn remove_from_token_total_supply_add_to_operations_v0( + &self, + token_id: [u8; 32], + amount: u64, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.remove_from_token_total_supply_operations_v0( + token_id, + amount, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn remove_from_token_total_supply_operations_v0( + &self, + token_id: [u8; 32], + amount: u64, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + // If we only estimate, add estimation costs + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + // Add your estimation logic similar to add_to_token_total_supply if needed + // For example (this is a placeholder method, you must implement similarly as others): + Self::add_estimation_costs_for_token_total_supply( + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let path_holding_total_token_supply = total_tokens_root_supply_path(); + let total_token_supply_in_platform = self + .grove_get_raw_value_u64_from_encoded_var_vec( + (&path_holding_total_token_supply).into(), + &token_id, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .ok_or(Error::Drive(DriveError::CriticalCorruptedState( + "Total supply for Token not found in Platform", + )))?; + let new_total = total_token_supply_in_platform + .checked_sub(amount) + .ok_or(Error::Drive(DriveError::CriticalCorruptedState( + "trying to subtract an amount that would underflow total supply", + )))?; + let path_holding_total_token_supply_vec = total_tokens_root_supply_path_vec(); + let replace_op = QualifiedGroveDbOp::replace_op( + path_holding_total_token_supply_vec, + token_id.to_vec(), + SumItem(new_total as i64, None), + ); + drive_operations.push(GroveOperation(replace_op)); + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/transfer/mod.rs b/packages/rs-drive/src/drive/tokens/transfer/mod.rs new file mode 100644 index 0000000000..bb18a9220b --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/transfer/mod.rs @@ -0,0 +1,106 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Transfers tokens from one identity to another without changing total supply. + pub fn token_transfer( + &self, + token_id: [u8; 32], + from_identity_id: [u8; 32], + to_identity_id: [u8; 32], + amount: u64, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.token.update.transfer { + 0 => self.token_transfer_v0( + token_id, + from_identity_id, + to_identity_id, + amount, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_transfer".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds operations to transfer tokens without calculating fees. + pub fn token_transfer_add_to_operations( + &self, + token_id: [u8; 32], + from_identity_id: [u8; 32], + to_identity_id: [u8; 32], + amount: u64, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.token.update.transfer { + 0 => self.token_transfer_add_to_operations_v0( + token_id, + from_identity_id, + to_identity_id, + amount, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_transfer_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Gathers the operations needed to transfer tokens. + pub fn token_transfer_operations( + &self, + token_id: [u8; 32], + from_identity_id: [u8; 32], + to_identity_id: [u8; 32], + amount: u64, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.update.transfer { + 0 => self.token_transfer_operations_v0( + token_id, + from_identity_id, + to_identity_id, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_transfer_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/transfer/v0/mod.rs b/packages/rs-drive/src/drive/tokens/transfer/v0/mod.rs new file mode 100644 index 0000000000..6e1f95689b --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/transfer/v0/mod.rs @@ -0,0 +1,114 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn token_transfer_v0( + &self, + token_id: [u8; 32], + from_identity_id: [u8; 32], + to_identity_id: [u8; 32], + amount: u64, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.token_transfer_add_to_operations_v0( + token_id, + from_identity_id, + to_identity_id, + amount, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn token_transfer_add_to_operations_v0( + &self, + token_id: [u8; 32], + from_identity_id: [u8; 32], + to_identity_id: [u8; 32], + amount: u64, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.token_transfer_operations_v0( + token_id, + from_identity_id, + to_identity_id, + amount, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn token_transfer_operations_v0( + &self, + token_id: [u8; 32], + from_identity_id: [u8; 32], + to_identity_id: [u8; 32], + amount: u64, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + drive_operations.extend(self.remove_from_identity_token_balance_operations( + token_id, + from_identity_id, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + drive_operations.extend(self.add_to_identity_token_balance_operations( + token_id, + to_identity_id, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?); + + // Total supply remains the same. + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/tokens/unfreeze/mod.rs b/packages/rs-drive/src/drive/tokens/unfreeze/mod.rs new file mode 100644 index 0000000000..0e483c0c24 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/unfreeze/mod.rs @@ -0,0 +1,95 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::Identifier; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Burns tokens by reducing the total supply and removing them from an identity's balance. + pub fn token_unfreeze( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version.drive.methods.token.update.unfreeze { + 0 => self.token_unfreeze_v0( + token_id, + frozen_identity_id, + block_info, + apply, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_unfreeze".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations to unfreeze tokens without calculating fees and optionally applying. + pub fn token_unfreeze_add_to_operations( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version.drive.methods.token.update.unfreeze { + 0 => self.token_unfreeze_add_to_operations_v0( + token_id, + frozen_identity_id, + apply, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_unfreeze_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Gathers the operations needed to unfreeze tokens. + pub fn token_unfreeze_operations( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version.drive.methods.token.update.unfreeze { + 0 => self.token_unfreeze_operations_v0( + token_id, + frozen_identity_id, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "token_unfreeze_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/unfreeze/v0/mod.rs b/packages/rs-drive/src/drive/tokens/unfreeze/v0/mod.rs new file mode 100644 index 0000000000..f9f0339a82 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/unfreeze/v0/mod.rs @@ -0,0 +1,147 @@ +use crate::drive::tokens::paths::token_identity_infos_path; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::identifier::Identifier; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; +use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::version::PlatformVersion; +use grovedb::{batch::KeyInfoPath, Element, EstimatedLayerInformation, TransactionArg, TreeType}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn token_unfreeze_v0( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + block_info: &BlockInfo, + apply: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + + self.token_unfreeze_add_to_operations_v0( + token_id, + frozen_identity_id, + apply, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fees = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + self.config.epochs_per_era, + platform_version, + None, + )?; + + Ok(fees) + } + + pub(super) fn token_unfreeze_add_to_operations_v0( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + apply: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut estimated_costs_only_with_layer_info = + if apply { None } else { Some(HashMap::new()) }; + + let batch_operations = self.token_unfreeze_operations_v0( + token_id, + frozen_identity_id, + &mut estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + + self.apply_batch_low_level_drive_operations( + estimated_costs_only_with_layer_info, + transaction, + batch_operations, + drive_operations, + &platform_version.drive, + ) + } + + pub(super) fn token_unfreeze_operations_v0( + &self, + token_id: Identifier, + frozen_identity_id: Identifier, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + Self::add_estimation_costs_for_token_identity_infos( + token_id.to_buffer(), + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + // no estimated_costs_only_with_layer_info, means we want to apply to state + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::NormalTree, + query_target: QueryTargetValue(8), + } + }; + + let token_info_path = token_identity_infos_path(token_id.as_bytes()); + match self + .grove_get_raw_optional_item( + (&token_info_path).into(), + frozen_identity_id.as_slice(), + direct_query_type, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .map(|bytes| IdentityTokenInfo::deserialize_from_bytes(&bytes)) + .transpose()? + { + None => { + let identity_token_info_bytes = IdentityTokenInfo::new(false, platform_version)? + .serialize_consume_to_bytes()?; + drive_operations.push(LowLevelDriveOperation::insert_for_known_path_key_element( + token_info_path.iter().map(|a| a.to_vec()).collect(), + frozen_identity_id.to_vec(), + Element::new_item(identity_token_info_bytes), + )); + } + Some(mut token_info) => { + if token_info.frozen() { + token_info.set_frozen(false); + let identity_token_info_bytes = token_info.serialize_consume_to_bytes()?; + drive_operations.push( + LowLevelDriveOperation::replace_for_known_path_key_element( + token_info_path.iter().map(|a| a.to_vec()).collect(), + frozen_identity_id.to_vec(), + Element::new_item(identity_token_info_bytes), + ), + ); + } + } + }; + + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_all_votes_given_by_identities/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_all_votes_given_by_identities/v0/mod.rs index 81b3d0fab7..2f2346d88b 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_all_votes_given_by_identities/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_all_votes_given_by_identities/v0/mod.rs @@ -15,7 +15,7 @@ use dpp::dashcore::Network; use dpp::prelude::{BlockHeight, Identifier}; use dpp::version::PlatformVersion; use grovedb::query_result_type::QueryResultType::QueryPathKeyElementTrioResultType; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::{MaybeTree, PathQuery, Query, SizedQuery, TransactionArg}; impl Drive { /// We remove votes for an identity when that identity is somehow disabled. Currently there is @@ -70,7 +70,7 @@ impl Drive { vote_path_ref.as_slice().into(), vote_id.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, &mut deletion_batch, @@ -106,7 +106,7 @@ impl Drive { absolute_path_ref.as_slice().into(), identifier_bytes.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, &mut deletion_batch, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v0/mod.rs index 5e9127abf6..3598e7b061 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v0/mod.rs @@ -8,7 +8,7 @@ use crate::util::grove_operations::BatchDeleteApplyType; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -33,7 +33,7 @@ impl Drive { path.as_slice().into(), resource_vote_choice.to_key().as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v1/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v1/mod.rs index 7440aaadce..4a2542b390 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v1/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_contenders_operations/v1/mod.rs @@ -10,7 +10,7 @@ use crate::util::grove_operations::BatchDeleteApplyType; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -35,7 +35,7 @@ impl Drive { path.as_slice().into(), resource_vote_choice.to_key().as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, @@ -47,7 +47,7 @@ impl Drive { path.as_slice().into(), &RESOURCE_ABSTAIN_VOTE_TREE_KEY_U8_32, BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, @@ -58,7 +58,7 @@ impl Drive { path.as_slice().into(), &RESOURCE_LOCK_VOTE_TREE_KEY_U8_32, BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v0/mod.rs index cb25558a38..c417c36cfb 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v0/mod.rs @@ -9,7 +9,7 @@ use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use grovedb::query_result_type::QueryResultType; -use grovedb::{PathQuery, TransactionArg}; +use grovedb::{MaybeTree, PathQuery, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; use std::ops::RangeFull; @@ -54,7 +54,7 @@ impl Drive { documents_storage_path.as_slice().into(), document_key.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, @@ -72,7 +72,7 @@ impl Drive { contender_path.as_slice().into(), vec![0].as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v1/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v1/mod.rs index f672267034..b21d9584fa 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v1/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_documents_operations/v1/mod.rs @@ -11,7 +11,7 @@ use dpp::document::DocumentV0Getters; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -70,7 +70,7 @@ impl Drive { documents_storage_path.as_slice().into(), document_key.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, @@ -89,7 +89,7 @@ impl Drive { contender_path.as_slice().into(), vec![0].as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v0/mod.rs index 1f2a36d353..4a0e7c0a4b 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v0/mod.rs @@ -8,7 +8,7 @@ use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use grovedb::batch::KeyInfoPath; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -34,7 +34,7 @@ impl Drive { // VotePoll Info 1 VotePoll Info 2 VotePoll Info 3 let delete_apply_type = BatchDeleteUpTreeApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }; for (vote_poll, end_date, _) in vote_polls { diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v1/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v1/mod.rs index b47e5feb60..ef35e8a2db 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v1/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_end_date_query_operations/v1/mod.rs @@ -12,7 +12,7 @@ use crate::util::grove_operations::BatchDeleteApplyType; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -38,7 +38,7 @@ impl Drive { // VotePoll Info 1 VotePoll Info 2 VotePoll Info 3 let delete_apply_type = BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }; let mut by_end_date: BTreeMap> = BTreeMap::new(); diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_info_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_info_operations/v0/mod.rs index 141fd3c766..0f30733b0a 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_info_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_info_operations/v0/mod.rs @@ -7,7 +7,7 @@ use crate::util::grove_operations::BatchDeleteApplyType; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -29,7 +29,7 @@ impl Drive { path.as_slice().into(), &RESOURCE_STORED_INFO_KEY_U8_32, BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_top_level_index_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_top_level_index_operations/v0/mod.rs index 13d3832592..d1a3583bf0 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_top_level_index_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_top_level_index_operations/v0/mod.rs @@ -7,7 +7,7 @@ use crate::util::grove_operations::BatchDeleteApplyType; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -30,7 +30,7 @@ impl Drive { path.as_slice().into(), last_index_path.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_votes_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_votes_operations/v0/mod.rs index 4bd8edcff9..44ee761e56 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_votes_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_contested_resource_vote_poll_votes_operations/v0/mod.rs @@ -7,7 +7,7 @@ use crate::util::grove_operations::BatchDeleteApplyType; use dpp::identifier::Identifier; use dpp::identity::TimestampMillis; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -36,7 +36,7 @@ impl Drive { path.as_slice().into(), vote.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, @@ -51,7 +51,7 @@ impl Drive { path.as_slice().into(), vec![VOTING_STORAGE_TREE_KEY].as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/cleanup/remove_specific_votes_given_by_identity/v0/mod.rs b/packages/rs-drive/src/drive/votes/cleanup/remove_specific_votes_given_by_identity/v0/mod.rs index bc8b467985..1802e9ab24 100644 --- a/packages/rs-drive/src/drive/votes/cleanup/remove_specific_votes_given_by_identity/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/cleanup/remove_specific_votes_given_by_identity/v0/mod.rs @@ -6,7 +6,7 @@ use crate::fees::op::LowLevelDriveOperation; use crate::util::grove_operations::BatchDeleteApplyType; use dpp::prelude::Identifier; use dpp::version::PlatformVersion; -use grovedb::TransactionArg; +use grovedb::{MaybeTree, TransactionArg}; impl Drive { /// We remove votes for an identity when that identity is somehow disabled. Currently there is @@ -29,7 +29,7 @@ impl Drive { vote_path_ref.as_slice().into(), vote_identifier_to_remove.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, batch_operations, diff --git a/packages/rs-drive/src/drive/votes/insert/contested_resource/individual_vote/register_contested_resource_identity_vote/v0/mod.rs b/packages/rs-drive/src/drive/votes/insert/contested_resource/individual_vote/register_contested_resource_identity_vote/v0/mod.rs index c7b284b845..2a1ddacfdd 100644 --- a/packages/rs-drive/src/drive/votes/insert/contested_resource/individual_vote/register_contested_resource_identity_vote/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/insert/contested_resource/individual_vote/register_contested_resource_identity_vote/v0/mod.rs @@ -16,7 +16,7 @@ use dpp::fee::fee_result::FeeResult; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use dpp::{bincode, ProtocolError}; use grovedb::reference_path::ReferencePathType; -use grovedb::{Element, TransactionArg}; +use grovedb::{Element, MaybeTree, TransactionArg, TreeType}; use platform_version::version::PlatformVersion; impl Drive { @@ -104,7 +104,7 @@ impl Drive { previous_voting_path.as_slice().into(), voter_pro_tx_hash.as_slice(), BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, true)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, &mut drive_operations, @@ -118,7 +118,7 @@ impl Drive { self.batch_insert_empty_tree_if_not_exists( PathKeyInfo::PathKey::<0>((votes_identities_path, voter_pro_tx_hash.to_vec())), - false, + TreeType::NormalTree, None, BatchInsertTreeApplyType::StatefulBatchInsertTree, //todo this shouldn't always be stateful transaction, diff --git a/packages/rs-drive/src/drive/votes/insert/vote_poll/add_vote_poll_end_date_query_operations/v0/mod.rs b/packages/rs-drive/src/drive/votes/insert/vote_poll/add_vote_poll_end_date_query_operations/v0/mod.rs index 1c5fb593e9..e3ac582a48 100644 --- a/packages/rs-drive/src/drive/votes/insert/vote_poll/add_vote_poll_end_date_query_operations/v0/mod.rs +++ b/packages/rs-drive/src/drive/votes/insert/vote_poll/add_vote_poll_end_date_query_operations/v0/mod.rs @@ -22,7 +22,7 @@ use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::ApproximateElements; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees}; use grovedb::EstimatedSumTrees::NoSumTrees; -use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg, TreeType}; use platform_version::version::PlatformVersion; use std::collections::HashMap; @@ -51,7 +51,7 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(vote_end_date_queries_tree_path()), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // We can estimate that there is at least a vote concluding every block, and we put blocks at 6 seconds. estimated_layer_count: ApproximateElements(201_600), estimated_layer_sizes: AllSubtrees( @@ -67,7 +67,7 @@ impl Drive { vote_contested_resource_end_date_queries_at_time_tree_path_vec(end_date), ), EstimatedLayerInformation { - is_sum_tree: false, + tree_type: TreeType::NormalTree, // We can estimate that there is 2 votes ending per block. estimated_layer_count: ApproximateElements(2), estimated_layer_sizes: AllItems( @@ -100,8 +100,8 @@ impl Drive { BatchInsertTreeApplyType::StatefulBatchInsertTree } else { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums: false, - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, + tree_type: TreeType::NormalTree, flags_len: storage_flags .as_ref() .map(|s| s.serialized_size()) @@ -113,7 +113,7 @@ impl Drive { // end data in the documents batch transition self.batch_insert_empty_tree_if_not_exists( path_key_info.clone(), - false, + TreeType::NormalTree, storage_flags.as_ref(), apply_type, transaction, @@ -133,7 +133,7 @@ impl Drive { BatchInsertApplyType::StatefulBatchInsert } else { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums: false, + in_tree_type: TreeType::NormalTree, // todo: figure out a default serialized size to make this faster target: QueryTargetValue( item.serialized_size(&platform_version.drive.grove_version)? as u32, diff --git a/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs b/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs index 2ca742ff8f..07006e2c19 100644 --- a/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs +++ b/packages/rs-drive/src/drive/votes/resolved/vote_polls/contested_document_resource_vote_poll/resolve.rs @@ -1,8 +1,10 @@ #[cfg(feature = "server")] use crate::drive::contract::DataContractFetchInfo; +#[cfg(feature = "server")] use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo; #[cfg(any(feature = "server", feature = "verify"))] use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed; +#[cfg(feature = "server")] use crate::drive::Drive; use crate::error::contract::DataContractError; use crate::error::Error; diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index c28ea60caa..f98c05096d 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -9,7 +9,7 @@ use grovedb::batch::key_info::KeyInfo; use grovedb::batch::KeyInfoPath; use grovedb::element::MaxReferenceHop; use grovedb::reference_path::ReferencePathType; -use grovedb::{batch::QualifiedGroveDbOp, Element, ElementFlags}; +use grovedb::{batch::QualifiedGroveDbOp, Element, ElementFlags, TreeType}; use grovedb_costs::OperationCost; use itertools::Itertools; @@ -382,6 +382,54 @@ impl LowLevelDriveOperation { LowLevelDriveOperation::insert_for_known_path_key_element(path, key, tree) } + /// Sets `GroveOperation` for inserting an empty sum tree at the given path and key + pub fn for_known_path_key_empty_big_sum_tree( + path: Vec>, + key: Vec, + storage_flags: Option<&StorageFlags>, + ) -> Self { + let tree = match storage_flags { + Some(storage_flags) => { + Element::new_big_sum_tree_with_flags(None, storage_flags.to_some_element_flags()) + } + None => Element::empty_big_sum_tree(), + }; + + LowLevelDriveOperation::insert_for_known_path_key_element(path, key, tree) + } + + /// Sets `GroveOperation` for inserting an empty count tree at the given path and key + pub fn for_known_path_key_empty_count_tree( + path: Vec>, + key: Vec, + storage_flags: Option<&StorageFlags>, + ) -> Self { + let tree = match storage_flags { + Some(storage_flags) => { + Element::new_count_tree_with_flags(None, storage_flags.to_some_element_flags()) + } + None => Element::empty_count_tree(), + }; + + LowLevelDriveOperation::insert_for_known_path_key_element(path, key, tree) + } + + /// Sets `GroveOperation` for inserting an empty count tree at the given path and key + pub fn for_known_path_key_empty_count_sum_tree( + path: Vec>, + key: Vec, + storage_flags: Option<&StorageFlags>, + ) -> Self { + let tree = match storage_flags { + Some(storage_flags) => { + Element::new_count_sum_tree_with_flags(None, storage_flags.to_some_element_flags()) + } + None => Element::new_count_sum_tree(None), + }; + + LowLevelDriveOperation::insert_for_known_path_key_element(path, key, tree) + } + /// Sets `GroveOperation` for inserting an empty tree at the given path and key pub fn for_estimated_path_key_empty_tree( path: KeyInfoPath, @@ -398,6 +446,22 @@ impl LowLevelDriveOperation { LowLevelDriveOperation::insert_for_estimated_path_key_element(path, key, tree) } + /// Sets `GroveOperation` for inserting an empty sum tree at the given path and key + pub fn for_estimated_path_key_empty_sum_tree( + path: KeyInfoPath, + key: KeyInfo, + storage_flags: Option<&StorageFlags>, + ) -> Self { + let tree = match storage_flags { + Some(storage_flags) => { + Element::empty_sum_tree_with_flags(storage_flags.to_some_element_flags()) + } + None => Element::empty_sum_tree(), + }; + + LowLevelDriveOperation::insert_for_estimated_path_key_element(path, key, tree) + } + /// Sets `GroveOperation` for inserting an element at the given path and key pub fn insert_for_known_path_key_element( path: Vec>, @@ -470,6 +534,38 @@ impl LowLevelDriveOperation { } } +/// A trait for getting an empty tree operation based on the tree type +pub trait LowLevelDriveOperationTreeTypeConverter { + /// Sets `GroveOperation` for inserting an empty tree at the given path and key + fn empty_tree_operation_for_known_path_key( + &self, + path: Vec>, + key: Vec, + storage_flags: Option<&StorageFlags>, + ) -> LowLevelDriveOperation; +} + +impl LowLevelDriveOperationTreeTypeConverter for TreeType { + /// Sets `GroveOperation` for inserting an empty tree at the given path and key + fn empty_tree_operation_for_known_path_key( + &self, + path: Vec>, + key: Vec, + storage_flags: Option<&StorageFlags>, + ) -> LowLevelDriveOperation { + let element_flags = storage_flags.map(|storage_flags| storage_flags.to_element_flags()); + let element = match self { + TreeType::NormalTree => Element::empty_tree_with_flags(element_flags), + TreeType::SumTree => Element::empty_sum_tree_with_flags(element_flags), + TreeType::BigSumTree => Element::empty_big_sum_tree_with_flags(element_flags), + TreeType::CountTree => Element::empty_count_tree_with_flags(element_flags), + TreeType::CountSumTree => Element::empty_count_sum_tree_with_flags(element_flags), + }; + + LowLevelDriveOperation::insert_for_known_path_key_element(path, key, element) + } +} + /// Drive cost trait pub trait DriveCost { /// Ephemeral cost diff --git a/packages/rs-drive/src/open/mod.rs b/packages/rs-drive/src/open/mod.rs index 8e2c599264..82e9a6c65c 100644 --- a/packages/rs-drive/src/open/mod.rs +++ b/packages/rs-drive/src/open/mod.rs @@ -4,9 +4,8 @@ use crate::config::DriveConfig; use crate::drive::Drive; use crate::error::Error; use dpp::errors::ProtocolError; -use dpp::util::deserializer::ProtocolVersion; use grovedb::GroveDb; -use platform_version::version::{PlatformVersion, INITIAL_PROTOCOL_VERSION}; +use platform_version::version::PlatformVersion; use std::path::Path; use std::sync::Arc; @@ -29,7 +28,8 @@ impl Drive { pub fn open>( path: P, config: Option, - ) -> Result<(Self, Option), Error> { + default_platform_version: Option<&PlatformVersion>, + ) -> Result<(Self, Option<&'static PlatformVersion>), Error> { let config = config.unwrap_or_default(); let grove = Arc::new(GroveDb::open(path)?); @@ -42,13 +42,18 @@ impl Drive { let data_contracts_global_cache_size = config.data_contracts_global_cache_size; let data_contracts_block_cache_size = config.data_contracts_block_cache_size; - let protocol_version = Drive::fetch_current_protocol_version_with_grovedb(&grove, None)?; + let maybe_protocol_version = + Drive::fetch_current_protocol_version_with_grovedb(&grove, None)?; + let maybe_platform_version = maybe_protocol_version + .map(|protocol_version| { + PlatformVersion::get(protocol_version).map_err(ProtocolError::PlatformVersionError) + }) + .transpose()?; // At this point we don't know the version what we need to process next block or initialize the chain // so version related data should be updated on init chain or on block execution - let platform_version = - PlatformVersion::get(protocol_version.unwrap_or(INITIAL_PROTOCOL_VERSION)) - .map_err(ProtocolError::PlatformVersionError)?; + let platform_version = maybe_platform_version + .unwrap_or_else(|| default_platform_version.unwrap_or(PlatformVersion::latest())); let drive = Drive { grove, @@ -66,6 +71,6 @@ impl Drive { }, }; - Ok((drive, protocol_version)) + Ok((drive, maybe_platform_version)) } } diff --git a/packages/rs-drive/src/query/contested_resource_votes_given_by_identity_query.rs b/packages/rs-drive/src/query/contested_resource_votes_given_by_identity_query.rs index b5b6938358..05c5ad8cfe 100644 --- a/packages/rs-drive/src/query/contested_resource_votes_given_by_identity_query.rs +++ b/packages/rs-drive/src/query/contested_resource_votes_given_by_identity_query.rs @@ -1,9 +1,13 @@ use crate::drive::votes::paths::vote_contested_resource_identity_votes_tree_path_for_identity_vec; +#[cfg(feature = "server")] use crate::drive::votes::storage_form::contested_document_resource_reference_storage_form::ContestedDocumentResourceVoteReferenceStorageForm; +#[cfg(feature = "server")] use crate::drive::votes::storage_form::contested_document_resource_storage_form::ContestedDocumentResourceVoteStorageForm; +#[cfg(feature = "server")] use crate::drive::votes::tree_path_storage_form::TreePathStorageForm; #[cfg(feature = "server")] use crate::drive::Drive; +#[cfg(feature = "server")] use crate::error::drive::DriveError; use crate::error::Error; #[cfg(feature = "server")] @@ -11,6 +15,7 @@ use crate::fees::op::LowLevelDriveOperation; #[cfg(feature = "server")] use crate::query::GroveError; use crate::query::Query; +#[cfg(feature = "server")] use dpp::bincode; #[cfg(feature = "server")] use dpp::block::block_info::BlockInfo; @@ -20,6 +25,7 @@ use grovedb::query_result_type::{QueryResultElements, QueryResultType}; #[cfg(feature = "server")] use grovedb::TransactionArg; use grovedb::{PathQuery, SizedQuery}; +#[cfg(feature = "server")] use platform_version::version::PlatformVersion; #[cfg(feature = "server")] use std::collections::BTreeMap; diff --git a/packages/rs-drive/src/query/drive_contested_document_query.rs b/packages/rs-drive/src/query/drive_contested_document_query.rs index e83950d6e0..375429edbc 100644 --- a/packages/rs-drive/src/query/drive_contested_document_query.rs +++ b/packages/rs-drive/src/query/drive_contested_document_query.rs @@ -1,4 +1,5 @@ use crate::drive::contract::paths::DataContractPaths; +#[cfg(feature = "server")] use crate::drive::Drive; use crate::error::Error; #[cfg(feature = "server")] @@ -6,6 +7,7 @@ use crate::fees::op::LowLevelDriveOperation; #[cfg(feature = "server")] use crate::query::GroveError; use crate::query::Query; +#[cfg(feature = "server")] use dpp::block::block_info::BlockInfo; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::document_type::DocumentTypeRef; diff --git a/packages/rs-drive/src/query/mod.rs b/packages/rs-drive/src/query/mod.rs index f6aa81deb2..5cdc6dcca6 100644 --- a/packages/rs-drive/src/query/mod.rs +++ b/packages/rs-drive/src/query/mod.rs @@ -2292,9 +2292,7 @@ mod tests { use serde_json::Value::Null; use crate::config::DriveConfig; - use crate::util::test_helpers::setup::{ - setup_drive_with_initial_state_structure, setup_system_data_contract, - }; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; use dpp::block::block_info::BlockInfo; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contracts::SystemDataContract; @@ -2310,10 +2308,11 @@ mod tests { fn setup_family_contract() -> (Drive, DataContract) { let tmp_dir = TempDir::new().unwrap(); - let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully"); - let platform_version = PlatformVersion::latest(); + let (drive, _) = Drive::open(tmp_dir, None, Some(platform_version)) + .expect("expected to open Drive successfully"); + drive .create_initial_state_structure(None, platform_version) .expect("expected to create root tree successfully"); @@ -2342,10 +2341,11 @@ mod tests { fn setup_withdrawal_contract() -> (Drive, DataContract) { let tmp_dir = TempDir::new().unwrap(); - let (drive, _) = Drive::open(tmp_dir, None).expect("expected to open Drive successfully"); - let platform_version = PlatformVersion::latest(); + let (drive, _) = Drive::open(tmp_dir, None, Some(platform_version)) + .expect("expected to open Drive successfully"); + drive .create_initial_state_structure(None, platform_version) .expect("expected to create root tree successfully"); diff --git a/packages/rs-drive/src/query/vote_poll_vote_state_query.rs b/packages/rs-drive/src/query/vote_poll_vote_state_query.rs index 1d2398918d..cf1f7ce4e9 100644 --- a/packages/rs-drive/src/query/vote_poll_vote_state_query.rs +++ b/packages/rs-drive/src/query/vote_poll_vote_state_query.rs @@ -4,6 +4,7 @@ use crate::drive::votes::paths::{ }; use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::resolve::ContestedDocumentResourceVotePollResolver; use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed; +#[cfg(feature = "server")] use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::query::QuerySyntaxError; @@ -16,6 +17,7 @@ use bincode::{Decode, Encode}; use dpp::block::block_info::BlockInfo; use dpp::data_contract::DataContract; use dpp::identifier::Identifier; +#[cfg(feature = "server")] use dpp::serialization::PlatformDeserializable; use dpp::voting::contender_structs::{ ContenderWithSerializedDocument, ContenderWithSerializedDocumentV0, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/batch_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/batch_transition.rs new file mode 100644 index 0000000000..31a9202237 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/batch_transition.rs @@ -0,0 +1,28 @@ +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +use dpp::prelude::Identifier; +use dpp::version::PlatformVersion; + +impl DriveHighLevelBatchOperationConverter for BatchedTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match self { + BatchedTransitionAction::DocumentAction(document_action) => document_action + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + BatchedTransitionAction::TokenAction(token_action) => token_action + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + BatchedTransitionAction::BumpIdentityDataContractNonce( + bump_identity_contract_nonce_action, + ) => bump_identity_contract_nonce_action + .into_high_level_drive_operations(epoch, platform_version), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_create_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs similarity index 95% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_create_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs index 96c16ed9e3..7a40ab8b47 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_create_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_create_transition.rs @@ -1,5 +1,5 @@ use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::util::batch::DriveOperation::{ DocumentOperation, IdentityOperation, PrefundedSpecializedBalanceOperation, }; @@ -12,15 +12,15 @@ use dpp::block::epoch::Epoch; use dpp::document::Document; use dpp::prelude::Identifier; use std::borrow::Cow; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0, DocumentFromCreateTransitionAction}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0, DocumentFromCreateTransitionAction}; use dpp::version::PlatformVersion; use crate::util::batch::drive_op_batch::PrefundedSpecializedBalanceOperationType; use crate::util::object_size_info::DataContractInfo::DataContractFetchInfo; use crate::error::drive::DriveError; -impl DriveHighLevelDocumentOperationConverter for DocumentCreateTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentCreateTransitionAction { + fn into_high_level_batch_drive_operations<'b>( mut self, epoch: &Epoch, owner_id: Identifier, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_delete_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs similarity index 86% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_delete_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs index 799f585778..b1622ca4d2 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_delete_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_delete_transition.rs @@ -1,4 +1,4 @@ -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::util::batch::DriveOperation::{DocumentOperation, IdentityOperation}; use crate::util::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; @@ -7,15 +7,15 @@ use crate::error::Error; use dpp::block::epoch::Epoch; use dpp::identifier::Identifier; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; use dpp::version::PlatformVersion; use crate::util::object_size_info::{DataContractInfo, DocumentTypeInfo}; use crate::error::drive::DriveError; -impl DriveHighLevelDocumentOperationConverter for DocumentDeleteTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentDeleteTransitionAction { + fn into_high_level_batch_drive_operations<'b>( self, _epoch: &Epoch, owner_id: Identifier, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_purchase_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs similarity index 92% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_purchase_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs index 3634442c28..63e6f118aa 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_purchase_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_purchase_transition.rs @@ -1,5 +1,5 @@ use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::util::batch::DriveOperation::{DocumentOperation, IdentityOperation}; use crate::util::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; use crate::util::object_size_info::DocumentInfo::DocumentOwnedInfo; @@ -9,13 +9,13 @@ use dpp::block::epoch::Epoch; use dpp::prelude::Identifier; use std::borrow::Cow; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::drive::DriveError; -impl DriveHighLevelDocumentOperationConverter for DocumentPurchaseTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentPurchaseTransitionAction { + fn into_high_level_batch_drive_operations<'b>( self, epoch: &Epoch, owner_id: Identifier, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_replace_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs similarity index 91% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_replace_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs index 19fb9febac..8cfaafa60e 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_replace_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_replace_transition.rs @@ -1,5 +1,5 @@ use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::util::batch::DriveOperation::{DocumentOperation, IdentityOperation}; use crate::util::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; use crate::util::object_size_info::DocumentInfo::DocumentOwnedInfo; @@ -10,13 +10,13 @@ use dpp::block::epoch::Epoch; use dpp::document::Document; use dpp::prelude::Identifier; use std::borrow::Cow; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentFromReplaceTransitionAction, DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentFromReplaceTransitionAction, DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::drive::DriveError; -impl DriveHighLevelDocumentOperationConverter for DocumentReplaceTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentReplaceTransitionAction { + fn into_high_level_batch_drive_operations<'b>( self, epoch: &Epoch, owner_id: Identifier, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs similarity index 91% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_transfer_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs index 67ea0f3bd1..65521399f8 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_transfer_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transfer_transition.rs @@ -1,5 +1,5 @@ use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::util::batch::DriveOperation::{DocumentOperation, IdentityOperation}; use crate::util::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; use crate::util::object_size_info::DocumentInfo::DocumentOwnedInfo; @@ -10,13 +10,13 @@ use dpp::block::epoch::Epoch; use dpp::document::DocumentV0Getters; use dpp::prelude::Identifier; use std::borrow::Cow; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::drive::DriveError; -impl DriveHighLevelDocumentOperationConverter for DocumentTransferTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentTransferTransitionAction { + fn into_high_level_batch_drive_operations<'b>( self, epoch: &Epoch, owner_id: Identifier, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transition.rs similarity index 63% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transition.rs index 38d4baf3ca..15e0a62f2e 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_transition.rs @@ -1,14 +1,13 @@ use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; -use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; -use crate::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use crate::util::batch::DriveOperation; use dpp::block::epoch::Epoch; use dpp::prelude::Identifier; use dpp::version::PlatformVersion; -impl DriveHighLevelDocumentOperationConverter for DocumentTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentTransitionAction { + fn into_high_level_batch_drive_operations<'b>( self, epoch: &Epoch, owner_id: Identifier, @@ -16,51 +15,47 @@ impl DriveHighLevelDocumentOperationConverter for DocumentTransitionAction { ) -> Result>, Error> { match self { DocumentTransitionAction::CreateAction(document_create_transition) => { - document_create_transition.into_high_level_document_drive_operations( + document_create_transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, ) } DocumentTransitionAction::ReplaceAction(document_replace_transition) => { - document_replace_transition.into_high_level_document_drive_operations( + document_replace_transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, ) } DocumentTransitionAction::DeleteAction(document_delete_transition) => { - document_delete_transition.into_high_level_document_drive_operations( + document_delete_transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, ) } DocumentTransitionAction::TransferAction(document_transfer_transition) => { - document_transfer_transition.into_high_level_document_drive_operations( + document_transfer_transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, ) } DocumentTransitionAction::PurchaseAction(document_purchase_transition) => { - document_purchase_transition.into_high_level_document_drive_operations( + document_purchase_transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, ) } DocumentTransitionAction::UpdatePriceAction(document_update_price_transition) => { - document_update_price_transition.into_high_level_document_drive_operations( + document_update_price_transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, ) } - DocumentTransitionAction::BumpIdentityDataContractNonce( - bump_identity_contract_nonce_action, - ) => bump_identity_contract_nonce_action - .into_high_level_drive_operations(epoch, platform_version), } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_update_price_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs similarity index 90% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_update_price_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs index abea0ffa63..f01e313a8a 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/document_update_price_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/document_update_price_transition.rs @@ -1,5 +1,5 @@ use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::util::batch::DriveOperation::{DocumentOperation, IdentityOperation}; use crate::util::batch::{DocumentOperationType, DriveOperation, IdentityOperationType}; use crate::util::object_size_info::DocumentInfo::DocumentOwnedInfo; @@ -9,13 +9,13 @@ use dpp::block::epoch::Epoch; use dpp::prelude::Identifier; use std::borrow::Cow; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; use crate::error::drive::DriveError; -impl DriveHighLevelDocumentOperationConverter for DocumentUpdatePriceTransitionAction { - fn into_high_level_document_drive_operations<'b>( +impl DriveHighLevelBatchOperationConverter for DocumentUpdatePriceTransitionAction { + fn into_high_level_batch_drive_operations<'b>( self, epoch: &Epoch, owner_id: Identifier, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/documents_batch_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/documents_batch_transition.rs similarity index 84% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/documents_batch_transition.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/documents_batch_transition.rs index eb1371efc2..652b3a3376 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/documents_batch_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/documents_batch_transition.rs @@ -1,13 +1,13 @@ use crate::error::drive::DriveError; use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::document::DriveHighLevelDocumentOperationConverter; +use crate::state_transition_action::action_convert_to_operations::batch::DriveHighLevelBatchOperationConverter; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; -use crate::state_transition_action::document::documents_batch::DocumentsBatchTransitionAction; +use crate::state_transition_action::batch::BatchTransitionAction; use crate::util::batch::DriveOperation; use dpp::block::epoch::Epoch; use dpp::version::PlatformVersion; -impl DriveHighLevelOperationConverter for DocumentsBatchTransitionAction { +impl DriveHighLevelOperationConverter for BatchTransitionAction { fn into_high_level_drive_operations<'b>( self, epoch: &Epoch, @@ -26,7 +26,7 @@ impl DriveHighLevelOperationConverter for DocumentsBatchTransitionAction { Ok(transitions .into_iter() .map(|transition| { - transition.into_high_level_document_drive_operations( + transition.into_high_level_batch_drive_operations( epoch, owner_id, platform_version, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/mod.rs new file mode 100644 index 0000000000..a6831026e3 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/document/mod.rs @@ -0,0 +1,8 @@ +mod document_create_transition; +mod document_delete_transition; +mod document_purchase_transition; +mod document_replace_transition; +mod document_transfer_transition; +mod document_transition; +mod document_update_price_transition; +mod documents_batch_transition; diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/mod.rs similarity index 57% rename from packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/mod.rs rename to packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/mod.rs index d473c995af..99c1c40408 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/document/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/mod.rs @@ -4,19 +4,14 @@ use dpp::block::epoch::Epoch; use dpp::platform_value::Identifier; use dpp::version::PlatformVersion; -mod document_create_transition; -mod document_delete_transition; -mod document_purchase_transition; -mod document_replace_transition; -mod document_transfer_transition; -mod document_transition; -mod document_update_price_transition; -mod documents_batch_transition; +mod batch_transition; +mod document; +mod token; /// A converter that will get High Level Drive Operations from State transitions -pub trait DriveHighLevelDocumentOperationConverter { +pub trait DriveHighLevelBatchOperationConverter { /// This will get a list of atomic drive operations from a high level operations - fn into_high_level_document_drive_operations<'a>( + fn into_high_level_batch_drive_operations<'a>( self, epoch: &Epoch, owner_id: Identifier, 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 new file mode 100644 index 0000000000..f4f2e61aa8 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/mod.rs @@ -0,0 +1,8 @@ +mod token_burn_transition; +mod token_destroy_frozen_funds_transition; +mod token_emergency_action_transition; +mod token_freeze_transition; +mod token_mint_transition; +mod token_transfer_transition; +mod token_transition; +mod token_unfreeze_transition; diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_burn_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_burn_transition.rs new file mode 100644 index 0000000000..b4d62088fc --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_burn_transition.rs @@ -0,0 +1,102 @@ +use dpp::block::epoch::Epoch; +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_burn_transition_action::{TokenBurnTransitionAction, TokenBurnTransitionActionAccessorsV0}; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenBurnTransitionAction { + 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_burn_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::Burn(self.burn_amount(), 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() { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id: self.token_id(), + identity_balance_holder_id: owner_id, + burn_amount: self.burn_amount(), + })); + + 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::Burn(self.burn_amount(), self.public_note_owned()), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenBurnTransitionAction::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_destroy_frozen_funds_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_destroy_frozen_funds_transition.rs new file mode 100644 index 0000000000..52b46800f9 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_destroy_frozen_funds_transition.rs @@ -0,0 +1,107 @@ +use dpp::block::epoch::Epoch; +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_destroy_frozen_funds_transition_action::{TokenDestroyFrozenFundsTransitionAction, TokenDestroyFrozenFundsTransitionActionAccessorsV0}; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenDestroyFrozenFundsTransitionAction { + 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_destroy_frozen_funds_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::DestroyFrozenFunds(self.frozen_identity_id(), self.amount(), 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() { + ops.push(TokenOperation(TokenOperationType::TokenBurn { + token_id: self.token_id(), + identity_balance_holder_id: self.frozen_identity_id(), + burn_amount: self.amount(), + })); + + 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::DestroyFrozenFunds( + self.frozen_identity_id(), + self.amount(), + self.public_note_owned(), + ), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenDestroyFrozenFundsTransitionAction::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_emergency_action_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_emergency_action_transition.rs new file mode 100644 index 0000000000..93a0899818 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_emergency_action_transition.rs @@ -0,0 +1,105 @@ +use dpp::block::epoch::Epoch; +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_emergency_action_transition_action::{TokenEmergencyActionTransitionAction, TokenEmergencyActionTransitionActionAccessorsV0}; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenEmergencyActionTransitionAction { + 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_emergency_action_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::EmergencyAction(self.emergency_action(), 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() { + ops.push(TokenOperation(TokenOperationType::TokenSetStatus { + token_id: self.token_id(), + status: self.emergency_action().resulting_status(platform_version)?, + })); + + 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::EmergencyAction( + self.emergency_action(), + self.public_note_owned(), + ), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenEmergencyActionTransitionAction::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_freeze_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_freeze_transition.rs new file mode 100644 index 0000000000..29eb030fce --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_freeze_transition.rs @@ -0,0 +1,105 @@ +use dpp::block::epoch::Epoch; +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_freeze_transition_action::{TokenFreezeTransitionAction, TokenFreezeTransitionActionAccessorsV0}; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenFreezeTransitionAction { + 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_freeze_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::Freeze(self.frozen_identity_id(), 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() { + ops.push(TokenOperation(TokenOperationType::TokenFreeze { + token_id: self.token_id(), + frozen_identity_id: self.frozen_identity_id(), + })); + + 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::Freeze( + self.frozen_identity_id(), + self.public_note_owned(), + ), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenFreezeTransitionAction::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_mint_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_mint_transition.rs new file mode 100644 index 0000000000..81cb0b2e1c --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_mint_transition.rs @@ -0,0 +1,111 @@ +use dpp::block::epoch::Epoch; +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_mint_transition_action::{TokenMintTransitionAction, TokenMintTransitionActionAccessorsV0}; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenMintTransitionAction { + 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_mint_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::Mint( + self.mint_amount(), + self.identity_balance_holder_id(), + 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() { + ops.push(TokenOperation(TokenOperationType::TokenMint { + token_id: self.token_id(), + identity_balance_holder_id: self.identity_balance_holder_id(), + mint_amount: self.mint_amount(), + allow_first_mint: false, + })); + + 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::Mint( + self.mint_amount(), + self.identity_balance_holder_id(), + self.public_note_owned(), + ), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenMintTransitionAction::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_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transfer_transition.rs new file mode 100644 index 0000000000..cb9db8c9b8 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transfer_transition.rs @@ -0,0 +1,84 @@ +use dpp::block::epoch::Epoch; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +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_transfer_transition_action::TokenTransferTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionAccessorsV0; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::TokenOperationType; +use crate::util::batch::DriveOperation::{IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenTransferTransitionAction { + 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_transfer_transition + { + 0 => { + let data_contract_id = self.base().data_contract_id(); + + let identity_contract_nonce = self.base().identity_contract_nonce(); + + let token_id = self.token_id(); + + let recipient_id = self.recipient_id(); + + let amount = self.amount(); + + let mut ops = vec![IdentityOperation( + IdentityOperationType::UpdateIdentityContractNonce { + identity_id: owner_id.into_buffer(), + contract_id: data_contract_id.into_buffer(), + nonce: identity_contract_nonce, + }, + )]; + + ops.push(TokenOperation(TokenOperationType::TokenTransfer { + token_id, + sender_id: owner_id, + recipient_id, + amount, + })); + + let token_configuration = self.base().token_configuration()?; + if token_configuration.keeps_history() { + let (public_note, shared_encrypted_note, private_encrypted_note) = + self.notes_owned(); + ops.push(TokenOperation(TokenOperationType::TokenHistory { + token_id, + owner_id, + nonce: identity_contract_nonce, + event: TokenEvent::Transfer( + recipient_id, + public_note, + shared_encrypted_note, + private_encrypted_note, + amount, + ), + })); + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenTransferTransitionAction::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 new file mode 100644 index 0000000000..adb128e016 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_transition.rs @@ -0,0 +1,105 @@ +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::TokenTransitionAction; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +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_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; +use crate::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::TokenMintTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_unfreeze_transition_action::TokenUnfreezeTransitionActionAccessorsV0; + +impl DriveHighLevelBatchOperationConverter for TokenTransitionAction { + fn into_high_level_batch_drive_operations<'b>( + self, + epoch: &Epoch, + owner_id: Identifier, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match self { + TokenTransitionAction::BurnAction(token_burn_transition) => token_burn_transition + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + TokenTransitionAction::MintAction(token_mint_transition) => token_mint_transition + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + TokenTransitionAction::TransferAction(token_transfer_transition) => { + token_transfer_transition.into_high_level_batch_drive_operations( + epoch, + owner_id, + platform_version, + ) + } + TokenTransitionAction::FreezeAction(token_freeze_action) => token_freeze_action + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + TokenTransitionAction::UnfreezeAction(token_unfreeze_action) => token_unfreeze_action + .into_high_level_batch_drive_operations(epoch, owner_id, platform_version), + TokenTransitionAction::EmergencyActionAction(token_emergency_action) => { + token_emergency_action.into_high_level_batch_drive_operations( + epoch, + owner_id, + platform_version, + ) + } + TokenTransitionAction::DestroyFrozenFundsAction(token_destroy_frozen_funds) => { + token_destroy_frozen_funds.into_high_level_batch_drive_operations( + epoch, + owner_id, + platform_version, + ) + } + } + } +} + +impl TokenTransitionAction { + /// Gets the associated token event for the transition action + pub fn associated_token_event(&self) -> TokenEvent { + match self { + TokenTransitionAction::BurnAction(burn_action) => TokenEvent::Burn( + burn_action.burn_amount(), + burn_action.public_note().cloned(), + ), + TokenTransitionAction::MintAction(mint_action) => TokenEvent::Mint( + mint_action.mint_amount(), + mint_action.identity_balance_holder_id(), + mint_action.public_note().cloned(), + ), + TokenTransitionAction::TransferAction(transfer_action) => { + let (public_note, shared_encrypted_note, private_encrypted_note) = + transfer_action.notes(); + TokenEvent::Transfer( + transfer_action.recipient_id(), + public_note, + shared_encrypted_note, + private_encrypted_note, + transfer_action.amount(), + ) + } + TokenTransitionAction::FreezeAction(freeze_action) => TokenEvent::Freeze( + freeze_action.frozen_identity_id(), + freeze_action.public_note().cloned(), + ), + TokenTransitionAction::UnfreezeAction(unfreeze_action) => TokenEvent::Unfreeze( + unfreeze_action.frozen_identity_id(), + unfreeze_action.public_note().cloned(), + ), + TokenTransitionAction::EmergencyActionAction(emergency_action) => { + TokenEvent::EmergencyAction( + emergency_action.emergency_action(), + emergency_action.public_note().cloned(), + ) + } + TokenTransitionAction::DestroyFrozenFundsAction(destroy_action) => { + TokenEvent::DestroyFrozenFunds( + destroy_action.frozen_identity_id(), + destroy_action.amount(), + destroy_action.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 new file mode 100644 index 0000000000..ca853cf564 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/batch/token/token_unfreeze_transition.rs @@ -0,0 +1,107 @@ +use dpp::block::epoch::Epoch; +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_unfreeze_transition_action::{TokenUnfreezeTransitionAction, TokenUnfreezeTransitionActionAccessorsV0}; +use crate::util::batch::{DriveOperation, IdentityOperationType}; +use crate::util::batch::drive_op_batch::{GroupOperationType, TokenOperationType}; +use crate::util::batch::DriveOperation::{GroupOperation, IdentityOperation, TokenOperation}; + +impl DriveHighLevelBatchOperationConverter for TokenUnfreezeTransitionAction { + 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_unfreeze_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::Unfreeze( + self.frozen_identity_id(), + 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() { + ops.push(TokenOperation(TokenOperationType::TokenUnfreeze { + token_id: self.token_id(), + frozen_identity_id: self.frozen_identity_id(), + })); + + 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::Freeze( + self.frozen_identity_id(), + self.public_note_owned(), + ), + })); + } + } + + Ok(ops) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "TokenUnfreezeTransitionAction::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/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs index bfc5b55e27..28c69e3f88 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs @@ -3,8 +3,8 @@ //! This module defines general, commonly used functions in Drive. //! +mod batch; mod contract; -mod document; mod identity; mod system; @@ -39,7 +39,7 @@ impl DriveHighLevelOperationConverter for StateTransitionAction { data_contract_update_transition .into_high_level_drive_operations(epoch, platform_version) } - StateTransitionAction::DocumentsBatchAction(documents_batch_transition) => { + StateTransitionAction::BatchAction(documents_batch_transition) => { documents_batch_transition.into_high_level_drive_operations(epoch, platform_version) } StateTransitionAction::IdentityCreateAction(identity_create_transition) => { diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs similarity index 100% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/mod.rs diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs similarity index 81% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs index 35a79fc023..a9bc78577f 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/transformer.rs @@ -2,13 +2,13 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; impl DocumentBaseTransitionAction { /// from base transition with contract lookup - pub fn from_base_transition_with_contract_lookup( + pub fn try_from_base_transition_with_contract_lookup( value: DocumentBaseTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -24,7 +24,7 @@ impl DocumentBaseTransitionAction { } /// from borrowed base transition with contract lookup - pub fn from_borrowed_base_transition_with_contract_lookup( + pub fn try_from_borrowed_base_transition_with_contract_lookup( value: &DocumentBaseTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs similarity index 100% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/mod.rs diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs similarity index 90% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs index b639eb421e..d64553ca35 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_base_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_base_transition_action/v0/transformer.rs @@ -3,9 +3,9 @@ use std::sync::Arc; use dpp::platform_value::Identifier; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dpp::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionV0; impl DocumentBaseTransitionActionV0 { /// try from base transition with contract lookup diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/mod.rs similarity index 98% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/mod.rs index 352444f830..e529985db7 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/mod.rs @@ -14,7 +14,7 @@ use dpp::fee::Credits; use dpp::ProtocolError; pub use v0::*; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction}; use dpp::version::PlatformVersion; use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo; use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs similarity index 86% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs index 50d8b830af..dab39d6d72 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/transformer.rs @@ -5,16 +5,16 @@ use grovedb::TransactionArg; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; +use dpp::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; use platform_version::version::PlatformVersion; use crate::drive::contract::DataContractFetchInfo; use crate::drive::Drive; use crate::error::Error; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionV0}; impl DocumentCreateTransitionAction { /// from_document_create_transition_with_contract_lookup - pub fn from_document_create_transition_with_contract_lookup( + pub fn try_from_document_create_transition_with_contract_lookup( drive: &Drive, transaction: TransactionArg, value: DocumentCreateTransition, @@ -31,7 +31,7 @@ impl DocumentCreateTransitionAction { } /// from_document_borrowed_create_transition_with_contract_lookup - pub fn from_document_borrowed_create_transition_with_contract_lookup( + pub fn try_from_document_borrowed_create_transition_with_contract_lookup( drive: &Drive, transaction: TransactionArg, value: &DocumentCreateTransition, diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/mod.rs similarity index 99% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/mod.rs index e61fbb73c9..e30b3948a7 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/mod.rs @@ -18,7 +18,7 @@ use dpp::document::property_names::{ }; use dpp::fee::Credits; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionV0}; use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo; use dpp::version::PlatformVersion; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs similarity index 95% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs index 2c2aea87be..5c7540f869 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_create_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_create_transition_action/v0/transformer.rs @@ -6,7 +6,7 @@ use grovedb::TransactionArg; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_create_transition::v0::DocumentCreateTransitionV0; +use dpp::state_transition::batch_transition::document_create_transition::v0::DocumentCreateTransitionV0; use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo; use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; use platform_version::version::PlatformVersion; @@ -15,8 +15,8 @@ use crate::drive::Drive; use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::resolve::ContestedDocumentResourceVotePollResolver; use crate::error::drive::DriveError; use crate::error::Error; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionActionV0; impl DocumentCreateTransitionActionV0 { /// try from document create transition with contract lookup @@ -34,7 +34,7 @@ impl DocumentCreateTransitionActionV0 { prefunded_voting_balance, .. } = value; - let base = DocumentBaseTransitionAction::from_base_transition_with_contract_lookup( + let base = DocumentBaseTransitionAction::try_from_base_transition_with_contract_lookup( base, get_data_contract, )?; @@ -130,7 +130,7 @@ impl DocumentCreateTransitionActionV0 { .. } = value; let base = - DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/mod.rs similarity index 87% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/mod.rs index 6ab5b5d730..bb6a09b381 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/mod.rs @@ -1,13 +1,13 @@ use derive_more::From; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::{DocumentDeleteTransitionActionAccessorsV0, DocumentDeleteTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::{DocumentDeleteTransitionActionAccessorsV0, DocumentDeleteTransitionActionV0}; /// transformer pub mod transformer; /// v0 pub mod v0; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; /// document delete transition action #[derive(Debug, Clone, From)] diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs similarity index 78% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs index da6cd644cc..ede80bd6f0 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/transformer.rs @@ -2,13 +2,13 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentDeleteTransition; +use dpp::state_transition::batch_transition::batched_transition::DocumentDeleteTransition; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::{DocumentDeleteTransitionAction, DocumentDeleteTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::{DocumentDeleteTransitionAction, DocumentDeleteTransitionActionV0}; impl DocumentDeleteTransitionAction { /// from - pub fn from_document_create_transition_with_contract_lookup( + pub fn try_from_document_create_transition_with_contract_lookup( value: DocumentDeleteTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { @@ -18,7 +18,7 @@ impl DocumentDeleteTransitionAction { } /// from borrowed - pub fn from_document_borrowed_create_transition_with_contract_lookup( + pub fn try_from_document_borrowed_create_transition_with_contract_lookup( value: &DocumentDeleteTransition, get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, ) -> Result { diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/mod.rs similarity index 89% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/mod.rs index 7df7f03744..c4e179c962 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/mod.rs @@ -1,7 +1,7 @@ /// transformer pub mod transformer; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; #[derive(Debug, Clone)] /// document delete transition action v0 diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs similarity index 74% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs index ff18328944..e3bbfeb289 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_delete_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_delete_transition_action/v0/transformer.rs @@ -2,10 +2,10 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionV0; impl DocumentDeleteTransitionActionV0 { /// try from @@ -15,7 +15,7 @@ impl DocumentDeleteTransitionActionV0 { ) -> Result { let DocumentDeleteTransitionV0 { base, .. } = value; Ok(DocumentDeleteTransitionActionV0 { - base: DocumentBaseTransitionAction::from_base_transition_with_contract_lookup( + base: DocumentBaseTransitionAction::try_from_base_transition_with_contract_lookup( base, get_data_contract, )?, @@ -29,7 +29,7 @@ impl DocumentDeleteTransitionActionV0 { ) -> Result { let DocumentDeleteTransitionV0 { base, .. } = value; Ok(DocumentDeleteTransitionActionV0 { - base: DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + base: DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, )?, diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/mod.rs similarity index 97% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/mod.rs index 53a84fe1a5..e91b681f10 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/mod.rs @@ -8,7 +8,7 @@ use dpp::platform_value::Identifier; use dpp::ProtocolError; pub use v0::*; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; use dpp::version::PlatformVersion; /// transformer diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs similarity index 87% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs index 894e13b5bd..7f591c601f 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/transformer.rs @@ -4,9 +4,9 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentPurchaseTransition; +use dpp::state_transition::batch_transition::batched_transition::DocumentPurchaseTransition; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionV0}; impl DocumentPurchaseTransitionAction { /// try from borrowed diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/mod.rs similarity index 94% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/mod.rs index 785ccb32b6..dd0fe6acb8 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/mod.rs @@ -4,7 +4,7 @@ use dpp::document::Document; use dpp::fee::Credits; use dpp::identifier::Identifier; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; /// document purchase transition action v0 #[derive(Debug, Clone)] diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs similarity index 86% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs index e888f20d33..f6131860b2 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_purchase_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_purchase_transition_action/v0/transformer.rs @@ -5,10 +5,10 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::document_purchase_transition::DocumentPurchaseTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_purchase_transition::DocumentPurchaseTransitionV0; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::v0::DocumentPurchaseTransitionActionV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::v0::DocumentPurchaseTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; impl DocumentPurchaseTransitionActionV0 { /// try from borrowed @@ -21,7 +21,7 @@ impl DocumentPurchaseTransitionActionV0 { ) -> Result { let DocumentPurchaseTransitionV0 { base, price, .. } = document_purchase_transition; let base = - DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/mod.rs similarity index 98% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/mod.rs index f2dfc222e3..01d8400b38 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/mod.rs @@ -11,7 +11,7 @@ use dpp::prelude::{BlockHeight, CoreBlockHeight, Revision}; use dpp::ProtocolError; pub use v0::*; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; use dpp::version::PlatformVersion; /// transformer diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs similarity index 91% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs index 4c5cfa6316..51f52bd4e6 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/transformer.rs @@ -5,9 +5,9 @@ use std::sync::Arc; use dpp::identity::TimestampMillis; use dpp::prelude::{BlockHeight, CoreBlockHeight}; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentReplaceTransition; +use dpp::state_transition::batch_transition::batched_transition::DocumentReplaceTransition; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionV0}; impl DocumentReplaceTransitionAction { /// try from borrowed diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/mod.rs similarity index 99% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/mod.rs index 299d71136f..f8b4daa0fd 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/mod.rs @@ -8,7 +8,7 @@ use dpp::ProtocolError; use std::collections::BTreeMap; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; use dpp::version::PlatformVersion; /// document replace transition action v0 diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs similarity index 88% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs index 8127c39532..b7d9ce25ed 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_replace_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_replace_transition_action/v0/transformer.rs @@ -6,10 +6,10 @@ use std::sync::Arc; use dpp::identity::TimestampMillis; use dpp::prelude::{BlockHeight, CoreBlockHeight}; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::v0::DocumentReplaceTransitionActionV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::v0::DocumentReplaceTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; impl DocumentReplaceTransitionActionV0 { /// try from borrowed @@ -31,7 +31,7 @@ impl DocumentReplaceTransitionActionV0 { .. } = document_replace_transition; let base = - DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/mod.rs similarity index 97% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/mod.rs index d9a38534ca..6dde44bf56 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/mod.rs @@ -7,7 +7,7 @@ use dpp::platform_value::Identifier; use dpp::ProtocolError; pub use v0::*; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; use dpp::version::PlatformVersion; /// transformer diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs similarity index 87% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs index 16bbaa4822..736d414f17 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/transformer.rs @@ -4,9 +4,9 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransferTransition; +use dpp::state_transition::batch_transition::batched_transition::DocumentTransferTransition; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionV0}; impl DocumentTransferTransitionAction { /// try from borrowed diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/mod.rs similarity index 92% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/mod.rs index d23667dd29..f87c75b622 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/mod.rs @@ -2,7 +2,7 @@ pub mod transformer; use dpp::document::Document; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; /// document transfer transition action v0 #[derive(Debug, Clone)] diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs similarity index 85% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs index 88f6d0776a..1bf629c41d 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_transfer_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transfer_transition_action/v0/transformer.rs @@ -5,10 +5,10 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::DocumentTransferTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::v0::DocumentTransferTransitionActionV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::v0::DocumentTransferTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; impl DocumentTransferTransitionActionV0 { /// try from borrowed @@ -24,7 +24,7 @@ impl DocumentTransferTransitionActionV0 { .. } = document_transfer_transition; let base = - DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transition_action_type.rs similarity index 63% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transition_action_type.rs index de03698b22..83d41158ea 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/action_type.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_transition_action_type.rs @@ -1,9 +1,9 @@ -use crate::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use dpp::state_transition::documents_batch_transition::document_transition::action_type::{ - DocumentTransitionActionType, TransitionActionTypeGetter, +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::{ + DocumentTransitionActionType, DocumentTransitionActionTypeGetter, }; -impl TransitionActionTypeGetter for DocumentTransitionAction { +impl DocumentTransitionActionTypeGetter for DocumentTransitionAction { fn action_type(&self) -> DocumentTransitionActionType { match self { DocumentTransitionAction::CreateAction(_) => DocumentTransitionActionType::Create, @@ -14,9 +14,6 @@ impl TransitionActionTypeGetter for DocumentTransitionAction { DocumentTransitionAction::UpdatePriceAction(_) => { DocumentTransitionActionType::UpdatePrice } - DocumentTransitionAction::BumpIdentityDataContractNonce(_) => { - DocumentTransitionActionType::IgnoreWhileBumpingRevision - } } } } diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/mod.rs similarity index 97% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/mod.rs index c206f21da9..254e3f803b 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/mod.rs @@ -7,7 +7,7 @@ use dpp::platform_value::Identifier; use dpp::ProtocolError; pub use v0::*; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; use dpp::version::PlatformVersion; /// transformer diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs similarity index 87% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs index f52e99d0d6..524ff7e6c1 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/transformer.rs @@ -4,9 +4,9 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentUpdatePriceTransition; +use dpp::state_transition::batch_transition::batched_transition::DocumentUpdatePriceTransition; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionV0}; impl DocumentUpdatePriceTransitionAction { /// try from borrowed diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/mod.rs similarity index 93% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/mod.rs index 37f3f8100c..493af12a6d 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/mod.rs @@ -2,7 +2,7 @@ pub mod transformer; use dpp::document::Document; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; /// document transfer transition action v0 #[derive(Debug, Clone)] diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs similarity index 84% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/transformer.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs index 6054d09f9b..c34bba6cb6 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/document_update_price_transition_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/document_update_price_transition_action/v0/transformer.rs @@ -5,10 +5,10 @@ use dpp::platform_value::Identifier; use std::sync::Arc; use dpp::ProtocolError; -use dpp::state_transition::documents_batch_transition::document_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_update_price_transition::DocumentUpdatePriceTransitionV0; use crate::drive::contract::DataContractFetchInfo; -use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::v0::DocumentUpdatePriceTransitionActionV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::v0::DocumentUpdatePriceTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::{DocumentBaseTransitionAction, DocumentBaseTransitionActionAccessorsV0}; impl DocumentUpdatePriceTransitionActionV0 { /// try from borrowed @@ -20,7 +20,7 @@ impl DocumentUpdatePriceTransitionActionV0 { ) -> Result { let DocumentUpdatePriceTransitionV0 { base, price, .. } = document_update_price_transition; let base = - DocumentBaseTransitionAction::from_borrowed_base_transition_with_contract_lookup( + DocumentBaseTransitionAction::try_from_borrowed_base_transition_with_contract_lookup( base, get_data_contract, )?; diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/mod.rs similarity index 51% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/mod.rs index 51c7f19d2d..7c40b64531 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/document_transition/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/document_transition/mod.rs @@ -1,4 +1,3 @@ -mod action_type; /// document_base_transition_action pub mod document_base_transition_action; /// document_create_transition_action @@ -11,22 +10,21 @@ pub mod document_purchase_transition_action; pub mod document_replace_transition_action; /// document_transfer_transition_action pub mod document_transfer_transition_action; +mod document_transition_action_type; /// document_update_price_transition_action pub mod document_update_price_transition_action; -pub use dpp::state_transition::documents_batch_transition::document_transition::action_type::DocumentTransitionActionType; +pub use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionType; use derive_more::From; - -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; -use crate::state_transition_action::document::documents_batch::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; -use crate::state_transition_action::document::documents_batch::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; -use crate::state_transition_action::document::documents_batch::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; -use crate::state_transition_action::document::documents_batch::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; -use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::{DocumentCreateTransitionAction, DocumentCreateTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::DocumentDeleteTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_replace_transition_action::{DocumentReplaceTransitionAction, DocumentReplaceTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_delete_transition_action::v0::DocumentDeleteTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::{DocumentPurchaseTransitionAction, DocumentPurchaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_transfer_transition_action::{DocumentTransferTransitionAction, DocumentTransferTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::document_transition::document_update_price_transition_action::{DocumentUpdatePriceTransitionAction, DocumentUpdatePriceTransitionActionAccessorsV0}; /// version pub const DOCUMENT_TRANSITION_ACTION_VERSION: u32 = 0; @@ -46,34 +44,30 @@ pub enum DocumentTransitionAction { PurchaseAction(DocumentPurchaseTransitionAction), /// update price UpdatePriceAction(DocumentUpdatePriceTransitionAction), - /// bump identity data contract nonce - BumpIdentityDataContractNonce(BumpIdentityDataContractNonceAction), } impl DocumentTransitionAction { /// base - pub fn base(&self) -> Option<&DocumentBaseTransitionAction> { + pub fn base(&self) -> &DocumentBaseTransitionAction { match self { - DocumentTransitionAction::CreateAction(d) => Some(d.base()), - DocumentTransitionAction::DeleteAction(d) => Some(d.base()), - DocumentTransitionAction::ReplaceAction(d) => Some(d.base()), - DocumentTransitionAction::TransferAction(d) => Some(d.base()), - DocumentTransitionAction::PurchaseAction(d) => Some(d.base()), - DocumentTransitionAction::UpdatePriceAction(d) => Some(d.base()), - DocumentTransitionAction::BumpIdentityDataContractNonce(_) => None, + DocumentTransitionAction::CreateAction(d) => d.base(), + DocumentTransitionAction::DeleteAction(d) => d.base(), + DocumentTransitionAction::ReplaceAction(d) => d.base(), + DocumentTransitionAction::TransferAction(d) => d.base(), + DocumentTransitionAction::PurchaseAction(d) => d.base(), + DocumentTransitionAction::UpdatePriceAction(d) => d.base(), } } /// base owned - pub fn base_owned(self) -> Option { + pub fn base_owned(self) -> DocumentBaseTransitionAction { match self { - DocumentTransitionAction::CreateAction(d) => Some(d.base_owned()), - DocumentTransitionAction::DeleteAction(d) => Some(d.base_owned()), - DocumentTransitionAction::ReplaceAction(d) => Some(d.base_owned()), - DocumentTransitionAction::TransferAction(d) => Some(d.base_owned()), - DocumentTransitionAction::PurchaseAction(d) => Some(d.base_owned()), - DocumentTransitionAction::UpdatePriceAction(d) => Some(d.base_owned()), - DocumentTransitionAction::BumpIdentityDataContractNonce(_) => None, + DocumentTransitionAction::CreateAction(d) => d.base_owned(), + DocumentTransitionAction::DeleteAction(d) => d.base_owned(), + DocumentTransitionAction::ReplaceAction(d) => d.base_owned(), + DocumentTransitionAction::TransferAction(d) => d.base_owned(), + DocumentTransitionAction::PurchaseAction(d) => d.base_owned(), + DocumentTransitionAction::UpdatePriceAction(d) => d.base_owned(), } } } diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs new file mode 100644 index 0000000000..4ba839bd84 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/mod.rs @@ -0,0 +1,40 @@ +use derive_more::From; +use dpp::identifier::Identifier; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; +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::TokenTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::{BumpIdentityDataContractNonceAction, BumpIdentityDataContractNonceActionAccessorsV0}; + +/// document transition +pub mod document_transition; +/// token transition +pub mod token_transition; + +/// token action +#[derive(Debug, Clone, From)] +pub enum BatchedTransitionAction { + /// document + DocumentAction(DocumentTransitionAction), + /// token + TokenAction(TokenTransitionAction), + /// bump identity data contract nonce + BumpIdentityDataContractNonce(BumpIdentityDataContractNonceAction), +} + +impl BatchedTransitionAction { + /// Helper method to get the data contract id + pub fn data_contract_id(&self) -> Identifier { + match self { + BatchedTransitionAction::DocumentAction(document_action) => { + document_action.base().data_contract_id() + } + BatchedTransitionAction::TokenAction(token_action) => { + token_action.base().data_contract_id() + } + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action) => { + bump_action.data_contract_id() + } + } + } +} 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 new file mode 100644 index 0000000000..af779c91c2 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/mod.rs @@ -0,0 +1,144 @@ +mod token_transition_action_type; + +/// token_base_transition_action +pub mod token_base_transition_action; +/// token_burn_transition_action +pub mod token_burn_transition_action; +/// token_freeze_transition_action +pub mod token_freeze_transition_action; +/// token_issuance_transition_action +pub mod token_mint_transition_action; +/// token_transfer_transition_action +pub mod token_transfer_transition_action; +/// token_unfreeze_transition_action +pub mod token_unfreeze_transition_action; + +/// token_destroy_frozen_funds_transition_action +pub mod token_destroy_frozen_funds_transition_action; +/// token_emergency_action_transition_action +pub mod token_emergency_action_transition_action; + +use derive_more::From; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::document_type::DocumentTypeRef; +use dpp::data_contracts::SystemDataContract; +use dpp::document::Document; +use dpp::identifier::Identifier; +use dpp::prelude::{DataContract, IdentityNonce}; +use dpp::ProtocolError; +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_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}; +use crate::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_emergency_action_transition_action::TokenEmergencyActionTransitionAction; +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_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_destroy_frozen_funds_transition_action::TokenDestroyFrozenFundsTransitionActionAccessorsV0; + +/// token action +#[derive(Debug, Clone, From)] +pub enum TokenTransitionAction { + /// burn + BurnAction(TokenBurnTransitionAction), + /// issuance + MintAction(TokenMintTransitionAction), + /// transfer + TransferAction(TokenTransferTransitionAction), + /// freeze + FreezeAction(TokenFreezeTransitionAction), + /// unfreeze + UnfreezeAction(TokenUnfreezeTransitionAction), + /// emergency action + EmergencyActionAction(TokenEmergencyActionTransitionAction), + /// destroy frozen funds action + DestroyFrozenFundsAction(TokenDestroyFrozenFundsTransitionAction), +} + +impl TokenTransitionAction { + /// Returns a reference to the base token transition action if available + pub fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenTransitionAction::BurnAction(action) => action.base(), + TokenTransitionAction::MintAction(action) => action.base(), + TokenTransitionAction::TransferAction(action) => action.base(), + TokenTransitionAction::FreezeAction(action) => action.base(), + TokenTransitionAction::UnfreezeAction(action) => action.base(), + TokenTransitionAction::EmergencyActionAction(action) => action.base(), + TokenTransitionAction::DestroyFrozenFundsAction(action) => action.base(), + } + } + + /// Consumes self and returns the base token transition action if available + pub fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenTransitionAction::BurnAction(action) => action.base_owned(), + TokenTransitionAction::MintAction(action) => action.base_owned(), + TokenTransitionAction::TransferAction(action) => action.base_owned(), + TokenTransitionAction::FreezeAction(action) => action.base_owned(), + TokenTransitionAction::UnfreezeAction(action) => action.base_owned(), + TokenTransitionAction::EmergencyActionAction(action) => action.base_owned(), + TokenTransitionAction::DestroyFrozenFundsAction(action) => action.base_owned(), + } + } + + /// Historical document type name for the token history contract + pub fn historical_document_type_name(&self) -> &str { + match self { + TokenTransitionAction::BurnAction(_) => "burn", + TokenTransitionAction::MintAction(_) => "mint", + TokenTransitionAction::TransferAction(_) => "transfer", + TokenTransitionAction::FreezeAction(_) => "freeze", + TokenTransitionAction::UnfreezeAction(_) => "unfreeze", + TokenTransitionAction::EmergencyActionAction(_) => "emergencyAction", + TokenTransitionAction::DestroyFrozenFundsAction(_) => "destroyFrozenFunds", + } + } + + /// Historical document type for the token history contract + pub fn historical_document_type<'a>( + &self, + token_history_contract: &'a DataContract, + ) -> Result, ProtocolError> { + Ok(token_history_contract.document_type_for_name(self.historical_document_type_name())?) + } + + /// Historical document id + pub fn historical_document_id( + &self, + owner_id: Identifier, + owner_nonce: IdentityNonce, + ) -> Identifier { + let name = self.historical_document_type_name(); + Document::generate_document_id_v0( + &SystemDataContract::TokenHistory.id(), + &owner_id, + name, + owner_nonce.to_be_bytes().as_slice(), + ) + } + + /// Historical document id + pub fn build_historical_document( + &self, + token_historical_contract: &DataContract, + token_id: Identifier, + owner_id: Identifier, + owner_nonce: IdentityNonce, + block_info: &BlockInfo, + ) -> Result { + self.associated_token_event() + .build_historical_document_owned( + token_historical_contract, + token_id, + owner_id, + owner_nonce, + block_info, + ) + .map_err(Error::Protocol) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/mod.rs new file mode 100644 index 0000000000..49b42cf17c --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/mod.rs @@ -0,0 +1,79 @@ +use derive_more::From; +use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; +use dpp::data_contract::TokenContractPosition; +use dpp::group::GroupStateTransitionResolvedInfo; +use dpp::platform_value::Identifier; +use dpp::prelude::IdentityNonce; +use std::sync::Arc; + +/// transformer module +pub mod transformer; +mod v0; + +use crate::drive::contract::DataContractFetchInfo; + +use crate::error::Error; +pub use v0::*; + +/// document base transition action +#[derive(Debug, Clone, From)] +pub enum TokenBaseTransitionAction { + /// v0 + V0(TokenBaseTransitionActionV0), +} + +impl TokenBaseTransitionActionAccessorsV0 for TokenBaseTransitionAction { + fn token_position(&self) -> TokenContractPosition { + match self { + TokenBaseTransitionAction::V0(v0) => v0.token_contract_position, + } + } + + fn token_id(&self) -> Identifier { + match self { + TokenBaseTransitionAction::V0(v0) => v0.token_id, + } + } + + fn data_contract_id(&self) -> Identifier { + match self { + TokenBaseTransitionAction::V0(v0) => v0.data_contract_id(), + } + } + + fn data_contract_fetch_info_ref(&self) -> &Arc { + match self { + TokenBaseTransitionAction::V0(v0) => v0.data_contract_fetch_info_ref(), + } + } + + fn data_contract_fetch_info(&self) -> Arc { + match self { + TokenBaseTransitionAction::V0(v0) => v0.data_contract_fetch_info(), + } + } + + fn token_configuration(&self) -> Result<&TokenConfiguration, Error> { + match self { + TokenBaseTransitionAction::V0(v0) => v0.token_configuration(), + } + } + + fn identity_contract_nonce(&self) -> IdentityNonce { + match self { + TokenBaseTransitionAction::V0(v0) => v0.identity_contract_nonce(), + } + } + + fn store_in_group(&self) -> Option<&GroupStateTransitionResolvedInfo> { + match self { + TokenBaseTransitionAction::V0(v0) => v0.store_in_group(), + } + } + + fn perform_action(&self) -> bool { + match self { + TokenBaseTransitionAction::V0(v0) => v0.perform_action(), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/transformer.rs new file mode 100644 index 0000000000..ab33951ffc --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/transformer.rs @@ -0,0 +1,69 @@ +use dpp::platform_value::Identifier; +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::prelude::ConsensusValidationResult; +use dpp::ProtocolError; +use dpp::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use platform_version::version::PlatformVersion; +use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionV0}; + +impl TokenBaseTransitionAction { + /// from base transition with contract lookup + pub fn try_from_base_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenBaseTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match value { + TokenBaseTransition::V0(v0) => Ok( + TokenBaseTransitionActionV0::try_from_base_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + drive_operations, + get_data_contract, + platform_version, + )? + .map(|v0| v0.into()), + ), + } + } + + /// from borrowed base transition with contract lookup + pub fn try_from_borrowed_base_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenBaseTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match value { + TokenBaseTransition::V0(v0) => Ok( + TokenBaseTransitionActionV0::try_from_borrowed_base_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + drive_operations, + get_data_contract, + platform_version, + )?.map(|v0| v0.into()) + ), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/mod.rs new file mode 100644 index 0000000000..9995478c57 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/mod.rs @@ -0,0 +1,112 @@ +use crate::drive::contract::DataContractFetchInfo; +use crate::error::Error; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; +use dpp::data_contract::TokenContractPosition; +use dpp::group::GroupStateTransitionResolvedInfo; +use dpp::identifier::Identifier; +use dpp::prelude::IdentityNonce; +use dpp::ProtocolError; +use std::sync::Arc; + +/// transformer +pub mod transformer; + +/// Token base transition action v0 +#[derive(Debug, Clone)] +pub struct TokenBaseTransitionActionV0 { + /// Token Id + pub token_id: Identifier, + /// The identity contract nonce, used to prevent replay attacks + pub identity_contract_nonce: IdentityNonce, + /// The token position within the data contract + pub token_contract_position: u16, + /// A potential data contract + pub data_contract: Arc, + /// Using group multi party rules for authentication + /// If this is set we should store in group + pub store_in_group: Option, + /// Should the action be performed. + /// This is true if we don't store in group. + /// And also true if we store in group and with this have enough signatures to perform the action + pub perform_action: bool, +} + +/// Token base transition action accessors v0 +pub trait TokenBaseTransitionActionAccessorsV0 { + /// The token position within the data contract + fn token_position(&self) -> TokenContractPosition; + + /// The token id + fn token_id(&self) -> Identifier; + + /// Returns the data contract ID + fn data_contract_id(&self) -> Identifier; + + /// Returns a reference to the data contract fetch info, without cloning + fn data_contract_fetch_info_ref(&self) -> &Arc; + + /// Returns the data contract fetch info (cloned Arc) + fn data_contract_fetch_info(&self) -> Arc; + + /// Returns the identity contract nonce + fn identity_contract_nonce(&self) -> IdentityNonce; + + /// Gets the token configuration associated to the action + fn token_configuration(&self) -> Result<&TokenConfiguration, Error>; + + /// Gets the store_in_group field (optional) + fn store_in_group(&self) -> Option<&GroupStateTransitionResolvedInfo>; + + /// Gets the perform_action field + fn perform_action(&self) -> bool; +} + +impl TokenBaseTransitionActionAccessorsV0 for TokenBaseTransitionActionV0 { + fn token_position(&self) -> u16 { + self.token_contract_position + } + + fn token_id(&self) -> Identifier { + self.token_id + } + + fn data_contract_id(&self) -> Identifier { + self.data_contract.contract.id() + } + + fn data_contract_fetch_info_ref(&self) -> &Arc { + &self.data_contract + } + + fn data_contract_fetch_info(&self) -> Arc { + self.data_contract.clone() + } + + fn identity_contract_nonce(&self) -> IdentityNonce { + self.identity_contract_nonce + } + + fn token_configuration(&self) -> Result<&TokenConfiguration, Error> { + self.data_contract + .as_ref() + .contract + .tokens() + .get(&self.token_contract_position) + .ok_or(Error::Protocol(ProtocolError::CorruptedCodeExecution( + format!( + "data contract does not have a token at position {}", + self.token_contract_position + ), + ))) + } + + fn store_in_group(&self) -> Option<&GroupStateTransitionResolvedInfo> { + self.store_in_group.as_ref() + } + + fn perform_action(&self) -> bool { + self.perform_action + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..64532238e7 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_base_transition_action/v0/transformer.rs @@ -0,0 +1,242 @@ +use dpp::group::{GroupStateTransitionInfo, GroupStateTransitionResolvedInfo}; +use dpp::platform_value::Identifier; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::consensus::ConsensusError; +use dpp::consensus::state::group::{GroupActionAlreadyCompletedError, GroupActionDoesNotExistError, IdentityNotMemberOfGroupError}; +use dpp::consensus::state::state_error::StateError; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::data_contract::group::accessors::v0::GroupV0Getters; +use dpp::prelude::ConsensusValidationResult; +use dpp::ProtocolError; +use dpp::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; +use platform_version::version::PlatformVersion; +use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionV0; + +impl TokenBaseTransitionActionV0 { + /// try from base transition with contract lookup + pub fn try_from_base_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenBaseTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let TokenBaseTransitionV0 { + token_contract_position, + data_contract_id, + identity_contract_nonce, + token_id, + using_group_info, + } = value; + + let data_contract = get_data_contract(data_contract_id)?; + + let (perform_action, store_in_group) = match using_group_info { + None => (true, None), + Some(GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer, + }) => { + let group = data_contract.contract.group(group_contract_position)?; + let signer_power = match group.member_power(owner_id) { + Ok(signer_power) => signer_power, + Err(ProtocolError::GroupMemberNotFound(_)) => { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityNotMemberOfGroupError( + IdentityNotMemberOfGroupError::new( + owner_id, + data_contract_id, + group_contract_position, + ), + )), + )); + } + Err(e) => return Err(e.into()), + }; + let required_power = group.required_power(); + let current_power = if action_is_proposer { + 0 + } else { + match drive.fetch_action_id_signers_power_and_add_operations( + data_contract_id, + group_contract_position, + action_id, + approximate_without_state_for_costs, + transaction, + drive_operations, + platform_version, + )? { + None => { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError( + StateError::GroupActionDoesNotExistError( + GroupActionDoesNotExistError::new( + data_contract_id, + group_contract_position, + action_id, + ), + ), + ), + )); + } + Some(power) => power, + } + }; + if current_power >= required_power { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::GroupActionAlreadyCompletedError( + GroupActionAlreadyCompletedError::new( + data_contract_id, + group_contract_position, + action_id, + ), + )), + )); + } + let perform_action = if approximate_without_state_for_costs { + // most expensive case is that we perform action + true + } else { + current_power + signer_power >= required_power + }; + let store_in_group = GroupStateTransitionResolvedInfo { + group_contract_position, + group: group.clone(), + action_id, + action_is_proposer, + signer_power, + }; + (perform_action, Some(store_in_group)) + } + }; + Ok(TokenBaseTransitionActionV0 { + token_id, + identity_contract_nonce, + token_contract_position, + data_contract, + store_in_group, + perform_action, + } + .into()) + } + + /// try from borrowed base transition with contract lookup + pub fn try_from_borrowed_base_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenBaseTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + drive_operations: &mut Vec, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let TokenBaseTransitionV0 { + token_contract_position, + data_contract_id, + identity_contract_nonce, + token_id, + using_group_info, + } = value; + + let data_contract = get_data_contract(*data_contract_id)?; + + let (perform_action, store_in_group) = match using_group_info { + None => (true, None), + Some(GroupStateTransitionInfo { + group_contract_position, + action_id, + action_is_proposer, + }) => { + let group = data_contract.contract.group(*group_contract_position)?; + let signer_power = match group.member_power(owner_id) { + Ok(signer_power) => signer_power, + Err(ProtocolError::GroupMemberNotFound(_)) => { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::IdentityNotMemberOfGroupError( + IdentityNotMemberOfGroupError::new( + owner_id, + *data_contract_id, + *group_contract_position, + ), + )), + )); + } + Err(e) => return Err(e.into()), + }; + let required_power = group.required_power(); + let current_power = if *action_is_proposer { + 0 + } else { + match drive.fetch_action_id_signers_power_and_add_operations( + *data_contract_id, + *group_contract_position, + *action_id, + approximate_without_state_for_costs, + transaction, + drive_operations, + platform_version, + )? { + None => { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError( + StateError::GroupActionDoesNotExistError( + GroupActionDoesNotExistError::new( + *data_contract_id, + *group_contract_position, + *action_id, + ), + ), + ), + )); + } + Some(power) => power, + } + }; + if current_power >= required_power { + return Ok(ConsensusValidationResult::new_with_error( + ConsensusError::StateError(StateError::GroupActionAlreadyCompletedError( + GroupActionAlreadyCompletedError::new( + *data_contract_id, + *group_contract_position, + *action_id, + ), + )), + )); + } + let perform_action = if approximate_without_state_for_costs { + // most expensive case is that we perform action + true + } else { + current_power + signer_power >= required_power + }; + let store_in_group = GroupStateTransitionResolvedInfo { + group_contract_position: *group_contract_position, + group: group.clone(), + action_id: *action_id, + action_is_proposer: *action_is_proposer, + signer_power, + }; + (perform_action, Some(store_in_group)) + } + }; + Ok(TokenBaseTransitionActionV0 { + token_id: *token_id, + identity_contract_nonce: *identity_contract_nonce, + token_contract_position: *token_contract_position, + data_contract, + store_in_group, + perform_action, + } + .into()) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/mod.rs new file mode 100644 index 0000000000..0e24f14920 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/mod.rs @@ -0,0 +1,60 @@ +use derive_more::From; + +/// transformer module for token burn transition action +pub mod transformer; +mod v0; + +pub use v0::*; // re-export the v0 module items (including TokenBurnTransitionActionV0) + +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; + +/// Token burn transition action +#[derive(Debug, Clone, From)] +pub enum TokenBurnTransitionAction { + /// v0 + V0(TokenBurnTransitionActionV0), +} + +impl TokenBurnTransitionActionAccessorsV0 for TokenBurnTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenBurnTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenBurnTransitionAction::V0(v0) => v0.base, + } + } + + fn burn_amount(&self) -> u64 { + match self { + TokenBurnTransitionAction::V0(v0) => v0.burn_amount, + } + } + + fn set_burn_amount(&mut self, amount: u64) { + match self { + TokenBurnTransitionAction::V0(v0) => v0.burn_amount = amount, + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenBurnTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenBurnTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenBurnTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/transformer.rs new file mode 100644 index 0000000000..92383d278b --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/transformer.rs @@ -0,0 +1,125 @@ +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_burn_transition_action::{ + TokenBurnTransitionAction, TokenBurnTransitionActionV0, +}; +use dpp::state_transition::batch_transition::token_burn_transition::TokenBurnTransition; +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 `TokenBurnTransition` into a `TokenBurnTransitionAction`. +impl TokenBurnTransitionAction { + /// Transform a `TokenBurnTransition` into a `TokenBurnTransitionAction` using the provided data contract lookup. + /// + /// This method processes a `TokenBurnTransition` and converts it into a `TokenBurnTransitionAction` while + /// looking up necessary data contracts and calculating transaction fees. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the burn transition. + /// * `value` - The `TokenBurnTransition` instance to be converted into a `TokenBurnTransitionAction`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state information. + /// * `transaction` - The transaction argument used for state changes. + /// * `block_info` - Block information needed to process the transition. + /// * `get_data_contract` - A closure that retrieves the `DataContractFetchInfo` for a given contract ID. + /// * `platform_version` - The platform version in use for the context of the transition. + /// + /// # Returns + /// + /// * `Result<(TokenBurnTransitionAction, FeeResult), Error>` - A result containing the `TokenBurnTransitionAction` and associated fees if successful, otherwise an error. + pub fn try_from_token_burn_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenBurnTransition, + 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 { + TokenBurnTransition::V0(v0) => { + TokenBurnTransitionActionV0::try_from_token_burn_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 `TokenBurnTransition` into a `TokenBurnTransitionAction` using the provided data contract lookup. + /// + /// This method processes a borrowed reference to a `TokenBurnTransition` and converts it into a `TokenBurnTransitionAction` + /// while looking up necessary data contracts and calculating transaction fees. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance used for accessing the system. + /// * `owner_id` - The identifier of the owner initiating the burn transition. + /// * `value` - A reference to the `TokenBurnTransition` to be converted into a `TokenBurnTransitionAction`. + /// * `approximate_without_state_for_costs` - A flag indicating whether to approximate state costs without full state information. + /// * `transaction` - The transaction argument used for state changes. + /// * `block_info` - Block information needed to process the transition. + /// * `get_data_contract` - A closure that retrieves the `DataContractFetchInfo` for a given contract ID. + /// * `platform_version` - The platform version in use for the context of the transition. + /// + /// # Returns + /// + /// * `Result<(TokenBurnTransitionAction, FeeResult), Error>` - A result containing the `TokenBurnTransitionAction` and associated fees if successful, otherwise an error. + pub fn try_from_borrowed_token_burn_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenBurnTransition, + 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 { + TokenBurnTransition::V0(v0) => { + TokenBurnTransitionActionV0::try_from_borrowed_token_burn_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_burn_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/v0/mod.rs new file mode 100644 index 0000000000..7a6c9a5184 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/v0/mod.rs @@ -0,0 +1,102 @@ +mod transformer; + +use std::sync::Arc; +use dpp::identifier::Identifier; +use dpp::prelude::IdentityNonce; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token burn transition action v0 +#[derive(Debug, Clone)] +pub struct TokenBurnTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The amount of tokens to burn + pub burn_amount: u64, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenBurnTransitionActionV0` +pub trait TokenBurnTransitionActionAccessorsV0 { + /// 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 amount of tokens to burn + fn burn_amount(&self) -> u64; + + /// Sets the amount of tokens to burn + fn set_burn_amount(&mut self, amount: u64); + + /// Returns a reference to the `public_note` field of the `TokenBurnTransitionActionV0` + fn public_note(&self) -> Option<&String>; + + /// Returns the owned `public_note` field of the `TokenBurnTransitionActionV0` + fn public_note_owned(self) -> Option; + + /// Sets the value of the `public_note` field in the `TokenBurnTransitionActionV0` + fn set_public_note(&mut self, public_note: Option); + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + 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 identity contract nonce + fn identity_contract_nonce(&self) -> IdentityNonce { + self.base().identity_contract_nonce() + } +} + +impl TokenBurnTransitionActionAccessorsV0 for TokenBurnTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn burn_amount(&self) -> u64 { + self.burn_amount + } + + fn set_burn_amount(&mut self, amount: u64) { + self.burn_amount = amount; + } + + 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_burn_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..1542acc0b2 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_burn_transition_action/v0/transformer.rs @@ -0,0 +1,229 @@ +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_burn_transition::v0::TokenBurnTransitionV0; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::UserFeeIncrease; +use dpp::validation::ConsensusValidationResult; +use platform_version::version::PlatformVersion; +use crate::drive::contract::DataContractFetchInfo; +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::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_burn_transition_action::v0::TokenBurnTransitionActionV0; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenBurnTransitionActionV0 { + /// Attempts to create a `TokenBurnTransitionActionV0` from the given `TokenBurnTransitionV0` value. + /// + /// This function extracts the necessary data from the provided `TokenBurnTransitionV0` and + /// delegates to the `try_from_base_transition_with_contract_lookup` function to construct the + /// base action. It then constructs the `TokenBurnTransitionActionV0` struct by including the + /// `burn_amount` and `public_note` values, along with the base action. + /// + /// # Parameters + /// - `drive`: A reference to the `Drive` struct which provides access to the system. + /// - `owner_id`: The identifier of the owner initiating the burn transition. + /// - `value`: The `TokenBurnTransitionV0` containing the details for the token burn. + /// - `approximate_without_state_for_costs`: A flag indicating whether to approximate state costs. + /// - `transaction`: The transaction argument used for state changes. + /// - `block_info`: Information about the current block to calculate fees. + /// - `get_data_contract`: A closure function that looks up the data contract for a given identifier. + /// - `platform_version`: The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// A `Result` containing the constructed `TokenBurnTransitionActionV0` on success, or an error + /// if any issues occur during the process. + /// + /// # Errors + /// - Returns an `Error` if any error occurs while trying to create the base action or process the burn. + pub fn try_from_token_burn_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenBurnTransitionV0, + 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 TokenBurnTransitionV0 { + base, + burn_amount, + 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::BurnAction( + TokenBurnTransitionActionV0 { + base: base_action, + burn_amount, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Attempts to create a `TokenBurnTransitionActionV0` from the borrowed `TokenBurnTransitionV0` value. + /// + /// This function is similar to `try_from_token_burn_transition_with_contract_lookup`, but it + /// operates on a borrowed `TokenBurnTransitionV0` to avoid ownership transfer. It delegates + /// to `try_from_borrowed_base_transition_with_contract_lookup` for constructing the base action, + /// then combines it with the `burn_amount` and `public_note` to form a `TokenBurnTransitionActionV0`. + /// + /// # Parameters + /// - `drive`: A reference to the `Drive` struct which provides access to the system. + /// - `owner_id`: The identifier of the owner initiating the burn transition. + /// - `value`: A borrowed reference to the `TokenBurnTransitionV0` containing the details for the token burn. + /// - `approximate_without_state_for_costs`: A flag indicating whether to approximate state costs. + /// - `transaction`: The transaction argument used for state changes. + /// - `block_info`: Information about the current block to calculate fees. + /// - `get_data_contract`: A closure function that looks up the data contract for a given identifier. + /// - `platform_version`: The platform version for the context in which the transition is being executed. + /// + /// # Returns + /// A `Result` containing the constructed `TokenBurnTransitionActionV0` on success, or an error + /// if any issues occur during the process. + /// + /// # Errors + /// - Returns an `Error` if any error occurs while trying to create the base action or process the burn. + pub fn try_from_borrowed_token_burn_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenBurnTransitionV0, + 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 TokenBurnTransitionV0 { + base, + burn_amount, + 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::BurnAction( + TokenBurnTransitionActionV0 { + base: base_action, + burn_amount: *burn_amount, + 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_destroy_frozen_funds_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/mod.rs new file mode 100644 index 0000000000..b3074af948 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/mod.rs @@ -0,0 +1,76 @@ +use derive_more::From; +use dpp::balances::credits::TokenAmount; +use dpp::identifier::Identifier; + +/// transformer module for token destroy_frozen_funds 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 destroy_frozen_funds transition action +#[derive(Debug, Clone, From)] +pub enum TokenDestroyFrozenFundsTransitionAction { + /// v0 + V0(TokenDestroyFrozenFundsTransitionActionV0), +} + +impl TokenDestroyFrozenFundsTransitionActionAccessorsV0 + for TokenDestroyFrozenFundsTransitionAction +{ + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.base, + } + } + + fn frozen_identity_id(&self) -> Identifier { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.frozen_identity_id, + } + } + + fn set_frozen_identity_id(&mut self, id: Identifier) { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.frozen_identity_id = id, + } + } + + fn amount(&self) -> TokenAmount { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.amount, + } + } + + fn set_amount(&mut self, amount: TokenAmount) { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.amount = amount, + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenDestroyFrozenFundsTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/transformer.rs new file mode 100644 index 0000000000..6b83b6e6a3 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_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_destroy_frozen_funds_transition_action::{TokenDestroyFrozenFundsTransitionActionV0, TokenDestroyFrozenFundsTransitionAction}; +use dpp::state_transition::batch_transition::token_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransition; +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 `TokenDestroyFrozenFundsTransition` into a `TokenDestroyFrozenFundsTransitionAction`. +impl TokenDestroyFrozenFundsTransitionAction { + /// Transform a `TokenDestroyFrozenFundsTransition` into a `TokenDestroyFrozenFundsTransitionAction` 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 destroy_frozen_funds transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenDestroyFrozenFundsTransition` 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 `TokenDestroyFrozenFundsTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_token_destroy_frozen_funds_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenDestroyFrozenFundsTransition, + 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 { + TokenDestroyFrozenFundsTransition::V0(v0) => { + TokenDestroyFrozenFundsTransitionActionV0::try_from_token_destroy_frozen_funds_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 `TokenDestroyFrozenFundsTransition` into a `TokenDestroyFrozenFundsTransitionAction` 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 destroy_frozen_funds transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenDestroyFrozenFundsTransition`. + /// * `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 `TokenDestroyFrozenFundsTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_destroy_frozen_funds_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenDestroyFrozenFundsTransition, + 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 { + TokenDestroyFrozenFundsTransition::V0(v0) => { + TokenDestroyFrozenFundsTransitionActionV0::try_from_borrowed_token_destroy_frozen_funds_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_destroy_frozen_funds_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/v0/mod.rs new file mode 100644 index 0000000000..9cbe01544e --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/v0/mod.rs @@ -0,0 +1,115 @@ +mod transformer; + +use std::sync::Arc; +use dpp::balances::credits::TokenAmount; +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 issuance transition action v0 +#[derive(Debug, Clone)] +pub struct TokenDestroyFrozenFundsTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The identity to credit the token to + pub frozen_identity_id: Identifier, + /// The amount that will be burned + pub amount: TokenAmount, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenIssuanceTransitionActionV0` +pub trait TokenDestroyFrozenFundsTransitionActionAccessorsV0 { + /// 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; + + /// Consumes self and returns the identity balance holder ID + fn frozen_identity_id(&self) -> Identifier; + + /// Sets the identity balance holder ID + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier); + + /// Returns the amount of tokens that the identity had and will be burned + fn amount(&self) -> TokenAmount; + + /// Sets the amount of tokens that the identity had and will be burned + fn set_amount(&mut self, amount: TokenAmount); + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + 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 TokenDestroyFrozenFundsTransitionActionAccessorsV0 + for TokenDestroyFrozenFundsTransitionActionV0 +{ + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn frozen_identity_id(&self) -> Identifier { + self.frozen_identity_id + } + + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + self.frozen_identity_id = frozen_identity_id; + } + + fn amount(&self) -> TokenAmount { + self.amount + } + + fn set_amount(&mut self, amount: TokenAmount) { + self.amount = amount; + } + + 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_destroy_frozen_funds_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..0b0ee7adbe --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_destroy_frozen_funds_transition_action/v0/transformer.rs @@ -0,0 +1,311 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::consensus::state::state_error::StateError; +use dpp::consensus::state::token::IdentityDoesNotHaveEnoughTokenBalanceError; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_destroy_frozen_funds_transition::v0::TokenDestroyFrozenFundsTransitionV0; +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_destroy_frozen_funds_transition_action::v0::TokenDestroyFrozenFundsTransitionActionV0; +use dpp::fee::fee_result::FeeResult; +use dpp::prelude::{ConsensusValidationResult, UserFeeIncrease}; +use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +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 TokenDestroyFrozenFundsTransitionActionV0 { + /// Converts a `TokenDestroyFrozenFundsTransitionV0` into a `TokenDestroyFrozenFundsTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token destroy_frozen_fundsing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for destroy_frozen_fundsing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the destroy_frozen_fundsing 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 `TokenDestroyFrozenFundsTransitionV0` 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 `TokenDestroyFrozenFundsTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + pub fn try_from_token_destroy_frozen_funds_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenDestroyFrozenFundsTransitionV0, + 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 TokenDestroyFrozenFundsTransitionV0 { + base, + frozen_identity_id, + 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 maybe_token_amount = drive.fetch_identity_token_balance_operations( + base.token_id().to_buffer(), + owner_id.to_buffer(), + !approximate_without_state_for_costs, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let Some(token_amount) = maybe_token_amount else { + 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(), + vec![StateError::IdentityDoesNotHaveEnoughTokenBalanceError( + IdentityDoesNotHaveEnoughTokenBalanceError::new( + base.token_id(), + frozen_identity_id, + 1, + 0, + "destroy_frozen_funds".to_string(), + ), + ) + .into()], + ), + fee_result, + )); + }; + + 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::DestroyFrozenFundsAction( + TokenDestroyFrozenFundsTransitionActionV0 { + base: base_action, + frozen_identity_id, + amount: token_amount, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Converts a borrowed `TokenDestroyFrozenFundsTransitionV0` into a `TokenDestroyFrozenFundsTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token destroy_frozen_fundsing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant destroy_frozen_fundsing 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 destroy_frozen_fundsing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenDestroyFrozenFundsTransitionV0` 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 + /// `TokenDestroyFrozenFundsTransitionActionV0` 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_destroy_frozen_funds_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenDestroyFrozenFundsTransitionV0, + 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 TokenDestroyFrozenFundsTransitionV0 { + base, + frozen_identity_id, + 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 maybe_token_amount = drive.fetch_identity_token_balance_operations( + base.token_id().to_buffer(), + owner_id.to_buffer(), + !approximate_without_state_for_costs, + transaction, + &mut drive_operations, + platform_version, + )?; + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + let Some(token_amount) = maybe_token_amount else { + 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(), + vec![StateError::IdentityDoesNotHaveEnoughTokenBalanceError( + IdentityDoesNotHaveEnoughTokenBalanceError::new( + base.token_id(), + *frozen_identity_id, + 1, + 0, + "destroy_frozen_funds".to_string(), + ), + ) + .into()], + ), + fee_result, + )); + }; + + 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::DestroyFrozenFundsAction( + TokenDestroyFrozenFundsTransitionActionV0 { + base: base_action, + frozen_identity_id: *frozen_identity_id, + amount: token_amount, + 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_emergency_action_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/mod.rs new file mode 100644 index 0000000000..4cd3b96c26 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/mod.rs @@ -0,0 +1,63 @@ +use derive_more::From; +use dpp::tokens::emergency_action::TokenEmergencyAction; + +/// transformer module for token emergency_action 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 emergency_action transition action +#[derive(Debug, Clone, From)] +pub enum TokenEmergencyActionTransitionAction { + /// v0 + V0(TokenEmergencyActionTransitionActionV0), +} + +impl TokenEmergencyActionTransitionActionAccessorsV0 for TokenEmergencyActionTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => v0.base, + } + } + + fn emergency_action(&self) -> TokenEmergencyAction { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => v0.emergency_action(), + } + } + + fn set_emergency_action(&mut self, emergency_action: TokenEmergencyAction) { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => { + v0.set_emergency_action(emergency_action) + } + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenEmergencyActionTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/transformer.rs new file mode 100644 index 0000000000..0e2670ed95 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_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_emergency_action_transition_action::{TokenEmergencyActionTransitionActionV0, TokenEmergencyActionTransitionAction}; +use dpp::state_transition::batch_transition::token_emergency_action_transition::TokenEmergencyActionTransition; +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 `TokenEmergencyActionTransition` into a `TokenEmergencyActionTransitionAction`. +impl TokenEmergencyActionTransitionAction { + /// Transform a `TokenEmergencyActionTransition` into a `TokenEmergencyActionTransitionAction` 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 emergency_action transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenEmergencyActionTransition` 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 `TokenEmergencyActionTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_token_emergency_action_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenEmergencyActionTransition, + 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 { + TokenEmergencyActionTransition::V0(v0) => { + TokenEmergencyActionTransitionActionV0::try_from_token_emergency_action_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 `TokenEmergencyActionTransition` into a `TokenEmergencyActionTransitionAction` 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 emergency_action transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenEmergencyActionTransition`. + /// * `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 `TokenEmergencyActionTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_emergency_action_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenEmergencyActionTransition, + 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 { + TokenEmergencyActionTransition::V0(v0) => { + TokenEmergencyActionTransitionActionV0::try_from_borrowed_token_emergency_action_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_emergency_action_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/v0/mod.rs new file mode 100644 index 0000000000..12dd5babe3 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/v0/mod.rs @@ -0,0 +1,97 @@ +mod transformer; + +use std::sync::Arc; +use dpp::identifier::Identifier; +use dpp::tokens::emergency_action::TokenEmergencyAction; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; + +/// Token issuance transition action v0 +#[derive(Debug, Clone)] +pub struct TokenEmergencyActionTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The emergency action + pub emergency_action: TokenEmergencyAction, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenIssuanceTransitionActionV0` +pub trait TokenEmergencyActionTransitionActionAccessorsV0 { + /// 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 `emergency_action` field. + fn emergency_action(&self) -> TokenEmergencyAction; + + /// Sets the value of the `emergency_action` field. + fn set_emergency_action(&mut self, emergency_action: TokenEmergencyAction); + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + 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 TokenEmergencyActionTransitionActionAccessorsV0 for TokenEmergencyActionTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn emergency_action(&self) -> TokenEmergencyAction { + self.emergency_action + } + + fn set_emergency_action(&mut self, emergency_action: TokenEmergencyAction) { + self.emergency_action = emergency_action; + } + + 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_emergency_action_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..b1d3b29459 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_emergency_action_transition_action/v0/transformer.rs @@ -0,0 +1,232 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_emergency_action_transition::v0::TokenEmergencyActionTransitionV0; +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_emergency_action_transition_action::v0::TokenEmergencyActionTransitionActionV0; +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 TokenEmergencyActionTransitionActionV0 { + /// Converts a `TokenEmergencyActionTransitionV0` into a `TokenEmergencyActionTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token emergency_actioning transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for emergency_actioning. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the emergency_actioning 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 `TokenEmergencyActionTransitionV0` 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 `TokenEmergencyActionTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + pub fn try_from_token_emergency_action_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenEmergencyActionTransitionV0, + 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 TokenEmergencyActionTransitionV0 { + base, + emergency_action, + 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::EmergencyActionAction( + TokenEmergencyActionTransitionActionV0 { + base: base_action, + emergency_action, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Converts a borrowed `TokenEmergencyActionTransitionV0` into a `TokenEmergencyActionTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token emergency_actioning transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant emergency_actioning 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 emergency_actioning transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenEmergencyActionTransitionV0` 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 + /// `TokenEmergencyActionTransitionActionV0` 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_emergency_action_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenEmergencyActionTransitionV0, + 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 TokenEmergencyActionTransitionV0 { + base, + emergency_action, + 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::EmergencyActionAction( + TokenEmergencyActionTransitionActionV0 { + base: base_action, + emergency_action: *emergency_action, + 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_freeze_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/mod.rs new file mode 100644 index 0000000000..f61d5d6d2e --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/mod.rs @@ -0,0 +1,61 @@ +use derive_more::From; +use dpp::identifier::Identifier; + +/// 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 freeze transition action +#[derive(Debug, Clone, From)] +pub enum TokenFreezeTransitionAction { + /// v0 + V0(TokenFreezeTransitionActionV0), +} + +impl TokenFreezeTransitionActionAccessorsV0 for TokenFreezeTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenFreezeTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenFreezeTransitionAction::V0(v0) => v0.base, + } + } + + fn frozen_identity_id(&self) -> Identifier { + match self { + TokenFreezeTransitionAction::V0(v0) => v0.frozen_identity_id, + } + } + + fn set_frozen_identity_id(&mut self, id: Identifier) { + match self { + TokenFreezeTransitionAction::V0(v0) => v0.frozen_identity_id = id, + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenFreezeTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenFreezeTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenFreezeTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/transformer.rs new file mode 100644 index 0000000000..3347e72524 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_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_freeze_transition_action::{TokenFreezeTransitionActionV0, TokenFreezeTransitionAction}; +use dpp::state_transition::batch_transition::token_freeze_transition::TokenFreezeTransition; +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 `TokenFreezeTransition` into a `TokenFreezeTransitionAction`. +impl TokenFreezeTransitionAction { + /// Transform a `TokenFreezeTransition` into a `TokenFreezeTransitionAction` 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 `TokenFreezeTransition` 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 `TokenFreezeTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_token_freeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenFreezeTransition, + 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 { + TokenFreezeTransition::V0(v0) => { + TokenFreezeTransitionActionV0::try_from_token_freeze_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 `TokenFreezeTransition` into a `TokenFreezeTransitionAction` 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 `TokenFreezeTransition`. + /// * `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 `TokenFreezeTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_freeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenFreezeTransition, + 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 { + TokenFreezeTransition::V0(v0) => { + TokenFreezeTransitionActionV0::try_from_borrowed_token_freeze_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_freeze_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/v0/mod.rs new file mode 100644 index 0000000000..80a912b127 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/v0/mod.rs @@ -0,0 +1,96 @@ +mod transformer; + +use std::sync::Arc; +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 issuance transition action v0 +#[derive(Debug, Clone)] +pub struct TokenFreezeTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The identity to credit the token to + pub frozen_identity_id: Identifier, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenIssuanceTransitionActionV0` +pub trait TokenFreezeTransitionActionAccessorsV0 { + /// 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; + + /// Consumes self and returns the identity balance holder ID + fn frozen_identity_id(&self) -> Identifier; + + /// Sets the identity balance holder ID + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier); + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + 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 TokenFreezeTransitionActionAccessorsV0 for TokenFreezeTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn frozen_identity_id(&self) -> Identifier { + self.frozen_identity_id + } + + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + self.frozen_identity_id = frozen_identity_id; + } + + 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_freeze_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..913dec97c6 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_freeze_transition_action/v0/transformer.rs @@ -0,0 +1,232 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_freeze_transition::v0::TokenFreezeTransitionV0; +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_freeze_transition_action::v0::TokenFreezeTransitionActionV0; +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 TokenFreezeTransitionActionV0 { + /// Converts a `TokenFreezeTransitionV0` into a `TokenFreezeTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token freezeing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for freezeing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the freezeing 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 `TokenFreezeTransitionV0` 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 `TokenFreezeTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + pub fn try_from_token_freeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenFreezeTransitionV0, + 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 TokenFreezeTransitionV0 { + base, + frozen_identity_id, + 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::FreezeAction( + TokenFreezeTransitionActionV0 { + base: base_action, + frozen_identity_id, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Converts a borrowed `TokenFreezeTransitionV0` into a `TokenFreezeTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token freezeing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant freezeing 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 freezeing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenFreezeTransitionV0` 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 + /// `TokenFreezeTransitionActionV0` 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_freeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenFreezeTransitionV0, + 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 TokenFreezeTransitionV0 { + base, + frozen_identity_id, + 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::FreezeAction( + TokenFreezeTransitionActionV0 { + base: base_action, + frozen_identity_id: *frozen_identity_id, + 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_mint_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/mod.rs new file mode 100644 index 0000000000..2c4b75de5e --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/mod.rs @@ -0,0 +1,73 @@ +use derive_more::From; +use dpp::identifier::Identifier; + +/// transformer module for token issuance 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 issuance transition action +#[derive(Debug, Clone, From)] +pub enum TokenMintTransitionAction { + /// v0 + V0(TokenMintTransitionActionV0), +} + +impl TokenMintTransitionActionAccessorsV0 for TokenMintTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenMintTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenMintTransitionAction::V0(v0) => v0.base, + } + } + + fn mint_amount(&self) -> u64 { + match self { + TokenMintTransitionAction::V0(v0) => v0.mint_amount, + } + } + + fn set_mint_amount(&mut self, amount: u64) { + match self { + TokenMintTransitionAction::V0(v0) => v0.mint_amount = amount, + } + } + + fn identity_balance_holder_id(&self) -> Identifier { + match self { + TokenMintTransitionAction::V0(v0) => v0.identity_balance_holder_id, + } + } + + fn set_identity_balance_holder_id(&mut self, id: Identifier) { + match self { + TokenMintTransitionAction::V0(v0) => v0.identity_balance_holder_id = id, + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenMintTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenMintTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenMintTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/transformer.rs new file mode 100644 index 0000000000..0183d1a7fd --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_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_mint_transition_action::{TokenMintTransitionActionV0, TokenMintTransitionAction}; +use dpp::state_transition::batch_transition::token_mint_transition::TokenMintTransition; +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 `TokenMintTransition` into a `TokenMintTransitionAction`. +impl TokenMintTransitionAction { + /// Transform a `TokenMintTransition` into a `TokenMintTransitionAction` 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 mint transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A `TokenMintTransition` 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 `TokenMintTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_token_mint_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenMintTransition, + 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 { + TokenMintTransition::V0(v0) => { + TokenMintTransitionActionV0::try_from_token_mint_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 `TokenMintTransition` into a `TokenMintTransitionAction` 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 mint transition. + /// * `transaction` - The transaction argument used for state changes. + /// * `value` - A reference to a `TokenMintTransition`. + /// * `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 `TokenMintTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_mint_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenMintTransition, + 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 { + TokenMintTransition::V0(v0) => { + TokenMintTransitionActionV0::try_from_borrowed_token_mint_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_mint_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/v0/mod.rs new file mode 100644 index 0000000000..812949c03c --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/v0/mod.rs @@ -0,0 +1,112 @@ +mod transformer; + +use std::sync::Arc; +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 issuance transition action v0 +#[derive(Debug, Clone)] +pub struct TokenMintTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The amount of tokens to create + pub mint_amount: u64, + /// The identity to credit the token to + pub identity_balance_holder_id: Identifier, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenIssuanceTransitionActionV0` +pub trait TokenMintTransitionActionAccessorsV0 { + /// 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 amount of tokens to issuance + fn mint_amount(&self) -> u64; + + /// Sets the amount of tokens to issuance + fn set_mint_amount(&mut self, amount: u64); + + /// Consumes self and returns the identity balance holder ID + fn identity_balance_holder_id(&self) -> Identifier; + + /// Sets the identity balance holder ID + fn set_identity_balance_holder_id(&mut self, id: Identifier); + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + 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 TokenMintTransitionActionAccessorsV0 for TokenMintTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn mint_amount(&self) -> u64 { + self.mint_amount + } + + fn set_mint_amount(&mut self, amount: u64) { + self.mint_amount = amount; + } + + fn identity_balance_holder_id(&self) -> Identifier { + self.identity_balance_holder_id + } + + fn set_identity_balance_holder_id(&mut self, id: Identifier) { + self.identity_balance_holder_id = id; + } + + 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_mint_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..5fba01b5e0 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_mint_transition_action/v0/transformer.rs @@ -0,0 +1,367 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::consensus::basic::BasicError; +use dpp::consensus::basic::token::{ChoosingTokenMintRecipientNotAllowedError, DestinationIdentityForTokenMintingNotSetError}; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_mint_transition::v0::TokenMintTransitionV0; +use dpp::ProtocolError; +use dpp::data_contract::accessors::v1::DataContractV1Getters; +use dpp::state_transition::batch_transition::token_base_transition::v0::v0_methods::TokenBaseTransitionV0Methods; +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0}; +use crate::state_transition_action::batch::batched_transition::token_transition::token_mint_transition_action::v0::TokenMintTransitionActionV0; +use dpp::data_contract::associated_token::token_configuration::accessors::v0::TokenConfigurationV0Getters; +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::token_transition::TokenTransitionAction; +use crate::state_transition_action::batch::BatchedTransitionAction; +use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceAction; + +impl TokenMintTransitionActionV0 { + /// Converts a `TokenMintTransitionV0` into a `TokenMintTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token minting transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for minting. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the minting 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 `TokenMintTransitionV0` 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 `TokenMintTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + pub fn try_from_token_mint_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenMintTransitionV0, + 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 TokenMintTransitionV0 { + base, + issued_to_identity_id, + amount, + public_note, + } = value; + + let position = base.token_contract_position(); + + 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, + )); + } + }; + + if !base_action + .token_configuration()? + .minting_allow_choosing_destination() + && issued_to_identity_id.is_some() + { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action( + &base_action, + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action.into(), + vec![BasicError::ChoosingTokenMintRecipientNotAllowedError( + ChoosingTokenMintRecipientNotAllowedError::new(base_action.token_id()), + ) + .into()], + ), + fee_result, + )); + } + + let identity_balance_holder_id = match issued_to_identity_id.or_else(|| { + base_action + .data_contract_fetch_info_ref() + .contract + .tokens() + .get(&position) + .and_then(|token_configuration| { + token_configuration.new_tokens_destination_identity() + }) + }) { + Some(identity_balance_holder_id) => identity_balance_holder_id, + None => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action( + &base_action, + owner_id, + 0, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action.into(), + vec![BasicError::DestinationIdentityForTokenMintingNotSetError( + DestinationIdentityForTokenMintingNotSetError::new( + base_action.token_id(), + ), + ) + .into()], + ), + fee_result, + )); + } + }; + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::MintAction( + TokenMintTransitionActionV0 { + base: base_action, + mint_amount: amount, + identity_balance_holder_id, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Converts a borrowed `TokenMintTransitionV0` into a `TokenMintTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token minting transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant minting 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 minting transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenMintTransitionV0` 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 + /// `TokenMintTransitionActionV0` 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_mint_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenMintTransitionV0, + 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 TokenMintTransitionV0 { + base, + issued_to_identity_id, + amount, + 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, + )); + } + }; + + if !base_action + .token_configuration()? + .minting_allow_choosing_destination() + && issued_to_identity_id.is_some() + { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action( + &base_action, + owner_id, + user_fee_increase, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action.into(), + vec![BasicError::ChoosingTokenMintRecipientNotAllowedError( + ChoosingTokenMintRecipientNotAllowedError::new(base_action.token_id()), + ) + .into()], + ), + fee_result, + )); + } + + let identity_balance_holder_id = match issued_to_identity_id.or_else(|| { + base_action + .data_contract_fetch_info_ref() + .contract + .tokens() + .get(&base.token_contract_position()) + .and_then(|token_configuration| { + token_configuration.new_tokens_destination_identity() + }) + }) { + Some(identity_balance_holder_id) => identity_balance_holder_id, + None => { + let bump_action = + BumpIdentityDataContractNonceAction::from_borrowed_token_base_transition_action( + &base_action, + owner_id, + 0, + ); + let batched_action = + BatchedTransitionAction::BumpIdentityDataContractNonce(bump_action); + + return Ok(( + ConsensusValidationResult::new_with_data_and_errors( + batched_action.into(), + vec![BasicError::DestinationIdentityForTokenMintingNotSetError( + DestinationIdentityForTokenMintingNotSetError::new( + base_action.token_id(), + ), + ) + .into()], + ), + fee_result, + )); + } + }; + + Ok(( + BatchedTransitionAction::TokenAction(TokenTransitionAction::MintAction( + TokenMintTransitionActionV0 { + base: base_action, + mint_amount: *amount, + identity_balance_holder_id, + 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_transfer_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/mod.rs new file mode 100644 index 0000000000..9202c66a24 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/mod.rs @@ -0,0 +1,157 @@ +use derive_more::From; + +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; +use dpp::identifier::Identifier; +use dpp::prelude::{DerivationEncryptionKeyIndex, RecipientKeyIndex, RootEncryptionKeyIndex, SenderKeyIndex}; + +/// transformer module +pub mod transformer; +/// v0 +pub mod v0; + +pub use v0::*; + +/// TokenTransferTransitionAction +#[derive(Debug, Clone, From)] +pub enum TokenTransferTransitionAction { + /// v0 + V0(TokenTransferTransitionActionV0), +} + +impl TokenTransferTransitionActionAccessorsV0 for TokenTransferTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenTransferTransitionAction::V0(v0) => v0.base(), + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenTransferTransitionAction::V0(v0) => v0.base_owned(), + } + } + + fn amount(&self) -> u64 { + match self { + TokenTransferTransitionAction::V0(v0) => v0.amount(), + } + } + + fn recipient_id(&self) -> Identifier { + match self { + TokenTransferTransitionAction::V0(v0) => v0.recipient_id(), + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenTransferTransitionAction::V0(v0) => v0.public_note(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenTransferTransitionAction::V0(v0) => v0.public_note_owned(), + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenTransferTransitionAction::V0(v0) => v0.set_public_note(public_note), + } + } + + fn shared_encrypted_note(&self) -> Option<&(SenderKeyIndex, RecipientKeyIndex, Vec)> { + match self { + TokenTransferTransitionAction::V0(v0) => v0.shared_encrypted_note(), + } + } + + fn shared_encrypted_note_owned(self) -> Option<(SenderKeyIndex, RecipientKeyIndex, Vec)> { + match self { + TokenTransferTransitionAction::V0(v0) => v0.shared_encrypted_note_owned(), + } + } + + fn set_shared_encrypted_note( + &mut self, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + ) { + match self { + TokenTransferTransitionAction::V0(v0) => { + v0.set_shared_encrypted_note(shared_encrypted_note) + } + } + } + + fn private_encrypted_note( + &self, + ) -> Option<&( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + match self { + TokenTransferTransitionAction::V0(v0) => v0.private_encrypted_note(), + } + } + + fn private_encrypted_note_owned( + self, + ) -> Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + match self { + TokenTransferTransitionAction::V0(v0) => v0.private_encrypted_note_owned(), + } + } + + fn set_private_encrypted_note( + &mut self, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + match self { + TokenTransferTransitionAction::V0(v0) => { + v0.set_private_encrypted_note(private_encrypted_note) + } + } + } + + fn notes( + &self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + match self { + TokenTransferTransitionAction::V0(v0) => v0.notes(), + } + } + + fn notes_owned( + self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + match self { + TokenTransferTransitionAction::V0(v0) => v0.notes_owned(), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/transformer.rs new file mode 100644 index 0000000000..3cf42ca910 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/transformer.rs @@ -0,0 +1,112 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use dpp::platform_value::Identifier; +use dpp::ProtocolError; +use dpp::state_transition::batch_transition::TokenTransferTransition; +use platform_version::version::PlatformVersion; +use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::TokenTransferTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_transfer_transition_action::v0::TokenTransferTransitionActionV0; + +/// Implement methods to transform a `TokenTransferTransition` into a `TokenTransferTransitionAction`. +impl TokenTransferTransitionAction { + /// Converts a `TokenTransferTransition` into a `TokenTransferTransitionAction` using the provided contract lookup. + /// + /// This function processes a `TokenTransferTransition` (which may contain multiple versions), looks up the necessary data + /// contracts, and calculates the associated fees for the transaction. Currently, only the `V0` variant of the transition is + /// supported. The result is a `TokenTransferTransitionAction` along with the fee result. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance for handling data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the token transfer. + /// * `value` - The `TokenTransferTransition` containing the transition data (currently only the `V0` variant is supported). + /// * `approximate_without_state_for_costs` - A flag to approximate transaction costs without full state consideration. + /// * `transaction` - The transaction context, which provides the necessary state for processing the transition. + /// * `block_info` - Information about the current block used to calculate fees for the transition. + /// * `get_data_contract` - A closure that takes an identifier and returns the associated `DataContractFetchInfo`. + /// * `platform_version` - The platform version to ensure the transition is compatible with the current version logic. + /// + /// # Returns + /// + /// * `Result<(TokenTransferTransitionAction, FeeResult), Error>` - A result containing the constructed `TokenTransferTransitionAction` + /// and the calculated `FeeResult`, or an error if the transition cannot be processed. + pub fn from_token_transfer_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenTransferTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result<(Self, FeeResult), Error> { + match value { + TokenTransferTransition::V0(v0) => { + let (v0, fee) = TokenTransferTransitionActionV0::try_from_token_transfer_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + get_data_contract, + platform_version, + )?; + Ok((v0.into(), fee)) + } + } + } + + /// Converts a borrowed reference of a `TokenTransferTransition` into a `TokenTransferTransitionAction` using the provided contract lookup. + /// + /// This function is similar to `from_token_transfer_transition_with_contract_lookup` but operates on a borrowed reference of the + /// `TokenTransferTransition`, which avoids copying the data. It processes the `TokenTransferTransition`, looks up the necessary + /// data contracts, and calculates the associated fees for the transaction. Only the `V0` variant of the transition is supported. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance for handling data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the token transfer. + /// * `value` - A borrowed reference to the `TokenTransferTransition` containing the transition data (currently only the `V0` variant is supported). + /// * `approximate_without_state_for_costs` - A flag to approximate transaction costs without full state consideration. + /// * `transaction` - The transaction context, which provides the necessary state for processing the transition. + /// * `block_info` - Information about the current block used to calculate fees for the transition. + /// * `get_data_contract` - A closure that takes an identifier and returns the associated `DataContractFetchInfo`. + /// * `platform_version` - The platform version to ensure the transition is compatible with the current version logic. + /// + /// # Returns + /// + /// * `Result<(TokenTransferTransitionAction, FeeResult), Error>` - A result containing the constructed `TokenTransferTransitionAction` + /// and the calculated `FeeResult`, or an error if the transition cannot be processed. + pub fn try_from_borrowed_token_transfer_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenTransferTransition, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result<(Self, FeeResult), Error> { + match value { + TokenTransferTransition::V0(v0) => { + let (v0, fee) = TokenTransferTransitionActionV0::try_from_borrowed_token_transfer_transition_with_contract_lookup( + drive, + owner_id, + v0, + approximate_without_state_for_costs, + transaction, + block_info, + get_data_contract, + platform_version, + )?; + Ok((v0.into(), fee)) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/mod.rs new file mode 100644 index 0000000000..962053117f --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/mod.rs @@ -0,0 +1,266 @@ +mod transformer; + +use std::sync::Arc; + +use dpp::identifier::Identifier; +use dpp::prelude::{ + DerivationEncryptionKeyIndex, IdentityNonce, RecipientKeyIndex, RootEncryptionKeyIndex, + SenderKeyIndex, +}; + +use crate::drive::contract::DataContractFetchInfo; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::{ + TokenBaseTransitionAction, TokenBaseTransitionActionAccessorsV0, +}; + +/// Token transfer transition action v0 +#[derive(Debug, Clone)] +pub struct TokenTransferTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The amount to transfer + pub amount: u64, + /// The recipient owner ID + pub recipient_id: Identifier, + /// The public note + pub public_note: Option, + /// An optional shared encrypted note + pub shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + /// An optional private encrypted note + pub private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, +} + +/// Accessors for `TokenTransferTransitionActionV0` +pub trait TokenTransferTransitionActionAccessorsV0 { + /// Returns the base token transition action + fn base(&self) -> &TokenBaseTransitionAction; + + /// Returns the base owned token transition action + fn base_owned(self) -> TokenBaseTransitionAction; + + /// Returns the amount of tokens to transfer + fn amount(&self) -> u64; + + /// Returns the recipient owner ID + fn recipient_id(&self) -> Identifier; + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + self.base().token_position() + } + + /// Returns the token ID + fn token_id(&self) -> Identifier { + self.base().token_id() + } + + /// Returns the data contract ID from the base action + fn data_contract_id(&self) -> Identifier { + self.base().data_contract_id() + } + + /// Returns a reference to the data contract fetch info from the base action + 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 identity contract nonce from the base action + fn identity_contract_nonce(&self) -> IdentityNonce { + self.base().identity_contract_nonce() + } + + /// Returns the public note, if present + fn public_note(&self) -> Option<&String>; + + /// Consumes the `TokenTransferTransitionActionV0` and returns the public note, if present + fn public_note_owned(self) -> Option; + + /// Sets the public note + fn set_public_note(&mut self, public_note: Option); + + /// Returns the shared encrypted note, if present + fn shared_encrypted_note(&self) -> Option<&(SenderKeyIndex, RecipientKeyIndex, Vec)>; + + /// Consumes the `TokenTransferTransitionActionV0` and returns the shared encrypted note, if present + fn shared_encrypted_note_owned(self) -> Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>; + + /// Sets the shared encrypted note + fn set_shared_encrypted_note( + &mut self, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + ); + + /// Returns the private encrypted note, if present + fn private_encrypted_note( + &self, + ) -> Option<&( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>; + + /// Consumes the `TokenTransferTransitionActionV0` and returns the private encrypted note, if present + fn private_encrypted_note_owned( + self, + ) -> Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>; + + /// Sets the private encrypted note + fn set_private_encrypted_note( + &mut self, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ); + + /// All notes + fn notes_owned( + self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ); + /// All notes + fn notes( + &self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ); +} + +impl TokenTransferTransitionActionAccessorsV0 for TokenTransferTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn amount(&self) -> u64 { + self.amount + } + + fn recipient_id(&self) -> Identifier { + self.recipient_id + } + + 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; + } + + fn shared_encrypted_note(&self) -> Option<&(SenderKeyIndex, RecipientKeyIndex, Vec)> { + self.shared_encrypted_note.as_ref() + } + + fn shared_encrypted_note_owned(self) -> Option<(SenderKeyIndex, RecipientKeyIndex, Vec)> { + self.shared_encrypted_note + } + + fn set_shared_encrypted_note( + &mut self, + shared_encrypted_note: Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + ) { + self.shared_encrypted_note = shared_encrypted_note; + } + + fn private_encrypted_note( + &self, + ) -> Option<&( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + self.private_encrypted_note.as_ref() + } + + fn private_encrypted_note_owned( + self, + ) -> Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )> { + self.private_encrypted_note + } + + fn set_private_encrypted_note( + &mut self, + private_encrypted_note: Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + self.private_encrypted_note = private_encrypted_note; + } + + fn notes( + &self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + ( + self.public_note.clone(), + self.shared_encrypted_note.clone(), + self.private_encrypted_note.clone(), + ) + } + + fn notes_owned( + self, + ) -> ( + Option, + Option<(SenderKeyIndex, RecipientKeyIndex, Vec)>, + Option<( + RootEncryptionKeyIndex, + DerivationEncryptionKeyIndex, + Vec, + )>, + ) { + ( + self.public_note, + self.shared_encrypted_note, + self.private_encrypted_note, + ) + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..8f652ae7d1 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transfer_transition_action/v0/transformer.rs @@ -0,0 +1,177 @@ +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_transfer_transition::v0::TokenTransferTransitionV0; +use dpp::ProtocolError; +use grovedb::TransactionArg; +use std::sync::Arc; +use dpp::block::block_info::BlockInfo; +use dpp::fee::fee_result::FeeResult; +use platform_version::version::PlatformVersion; +use crate::drive::contract::DataContractFetchInfo; +use crate::drive::Drive; +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_transfer_transition_action::TokenTransferTransitionActionV0; + +impl TokenTransferTransitionActionV0 { + /// Converts a `TokenTransferTransitionV0` into a `TokenTransferTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token transfer transition, looks up the necessary data contracts, performs required + /// checks, and applies the relevant logic for token transfer. It also calculates the fees associated with the transaction. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the transfer. + /// * `value` - The `TokenTransferTransitionV0` struct containing the transition data, including token amount, + /// recipient details, and encrypted notes. + /// * `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 transaction cost calculations when full state is not needed. + /// * `transaction` - The transaction context, which includes state details and necessary operations for the transition. + /// * `block_info` - Information about the current block to calculate the fees for the transition. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns the associated `DataContractFetchInfo`. + /// * `platform_version` - A reference to the platform version, ensuring that the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result<(TokenTransferTransitionActionV0, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenTransferTransitionActionV0` and the calculated `FeeResult` if successful, or an error if the transition cannot + /// be created or an issue arises with the provided state or data. + pub fn try_from_token_transfer_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenTransferTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result<(Self, FeeResult), Error> { + let TokenTransferTransitionV0 { + base, + amount, + recipient_id, + public_note, + shared_encrypted_note, + private_encrypted_note, + } = value; + + let mut drive_operations = vec![]; + + // Lookup the base action using the base transition data and contract information + let base_action = TokenBaseTransitionAction::try_from_base_transition_with_contract_lookup( + drive, + owner_id, + base, + approximate_without_state_for_costs, + transaction, + &mut drive_operations, + get_data_contract, + platform_version, + )? + .into_data()?; + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + // Return the TokenTransferTransitionActionV0 with the relevant data + Ok(( + TokenTransferTransitionActionV0 { + base: base_action, + amount, + recipient_id, + public_note, + shared_encrypted_note, + private_encrypted_note, + }, + fee_result, + )) + } + + /// Converts a borrowed `TokenTransferTransitionV0` into a `TokenTransferTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token transfer transition similarly to the `try_from_token_transfer_transition_with_contract_lookup` + /// method but operates on a borrowed reference of the `TokenTransferTransitionV0`. It performs the same checks and applies + /// the token transfer logic, while avoiding copying the `TokenTransferTransitionV0` struct. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the transfer. + /// * `value` - A reference to the `TokenTransferTransitionV0` struct containing the transition data, including token amount, + /// recipient details, and encrypted notes. + /// * `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 transaction cost calculations when full state is not needed. + /// * `transaction` - The transaction context, which includes state details and necessary operations for the transition. + /// * `block_info` - Information about the current block to calculate the fees for the transition. + /// * `get_data_contract` - A closure function that takes a contract identifier and returns the associated `DataContractFetchInfo`. + /// * `platform_version` - A reference to the platform version, ensuring that the transition respects version-specific logic. + /// + /// # Returns + /// + /// * `Result<(TokenTransferTransitionActionV0, FeeResult), Error>` - Returns a tuple containing the constructed + /// `TokenTransferTransitionActionV0` and the calculated `FeeResult` if successful, or an error if the transition cannot + /// be created or an issue arises with the provided state or data. + pub fn try_from_borrowed_token_transfer_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenTransferTransitionV0, + approximate_without_state_for_costs: bool, + transaction: TransactionArg, + block_info: &BlockInfo, + get_data_contract: impl Fn(Identifier) -> Result, ProtocolError>, + platform_version: &PlatformVersion, + ) -> Result<(Self, FeeResult), Error> { + let TokenTransferTransitionV0 { + base, + amount, + recipient_id, + public_note, + shared_encrypted_note, + private_encrypted_note, + } = value; + + let mut drive_operations = vec![]; + + // Lookup the base action using the borrowed base transition data and contract information + let base_action = + 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, + )? + .into_data()?; + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + + // Return the TokenTransferTransitionActionV0 with the relevant data + Ok(( + TokenTransferTransitionActionV0 { + base: base_action.into(), + amount: *amount, + recipient_id: *recipient_id, + public_note: public_note.clone(), + shared_encrypted_note: shared_encrypted_note.clone(), + private_encrypted_note: private_encrypted_note.clone(), + }, + 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 new file mode 100644 index 0000000000..69689509bc --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_transition_action_type.rs @@ -0,0 +1,22 @@ +use crate::state_transition_action::batch::batched_transition::token_transition::TokenTransitionAction; +use dpp::state_transition::batch_transition::batched_transition::token_transition_action_type::{ + TokenTransitionActionType, TokenTransitionActionTypeGetter, +}; + +impl TokenTransitionActionTypeGetter for TokenTransitionAction { + fn action_type(&self) -> TokenTransitionActionType { + match self { + TokenTransitionAction::BurnAction(_) => TokenTransitionActionType::Burn, + TokenTransitionAction::MintAction(_) => TokenTransitionActionType::Mint, + TokenTransitionAction::TransferAction(_) => TokenTransitionActionType::Transfer, + TokenTransitionAction::FreezeAction(_) => TokenTransitionActionType::Freeze, + TokenTransitionAction::UnfreezeAction(_) => TokenTransitionActionType::Unfreeze, + TokenTransitionAction::EmergencyActionAction(_) => { + TokenTransitionActionType::EmergencyAction + } + TokenTransitionAction::DestroyFrozenFundsAction(_) => { + TokenTransitionActionType::DestroyFrozenFunds + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/mod.rs new file mode 100644 index 0000000000..ec55cb2835 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/mod.rs @@ -0,0 +1,61 @@ +use derive_more::From; +use dpp::identifier::Identifier; + +/// 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 freeze transition action +#[derive(Debug, Clone, From)] +pub enum TokenUnfreezeTransitionAction { + /// v0 + V0(TokenUnfreezeTransitionActionV0), +} + +impl TokenUnfreezeTransitionActionAccessorsV0 for TokenUnfreezeTransitionAction { + fn base(&self) -> &TokenBaseTransitionAction { + match self { + TokenUnfreezeTransitionAction::V0(v0) => &v0.base, + } + } + + fn base_owned(self) -> TokenBaseTransitionAction { + match self { + TokenUnfreezeTransitionAction::V0(v0) => v0.base, + } + } + + fn frozen_identity_id(&self) -> Identifier { + match self { + TokenUnfreezeTransitionAction::V0(v0) => v0.frozen_identity_id, + } + } + + fn set_frozen_identity_id(&mut self, id: Identifier) { + match self { + TokenUnfreezeTransitionAction::V0(v0) => v0.frozen_identity_id = id, + } + } + + fn public_note(&self) -> Option<&String> { + match self { + TokenUnfreezeTransitionAction::V0(v0) => v0.public_note.as_ref(), + } + } + + fn public_note_owned(self) -> Option { + match self { + TokenUnfreezeTransitionAction::V0(v0) => v0.public_note, + } + } + + fn set_public_note(&mut self, public_note: Option) { + match self { + TokenUnfreezeTransitionAction::V0(v0) => v0.public_note = public_note, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/transformer.rs new file mode 100644 index 0000000000..14df0f2fdf --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_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_unfreeze_transition_action::{TokenUnfreezeTransitionActionV0, TokenUnfreezeTransitionAction}; +use dpp::state_transition::batch_transition::token_unfreeze_transition::TokenUnfreezeTransition; +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 `TokenUnfreezeTransition` into a `TokenUnfreezeTransitionAction`. +impl TokenUnfreezeTransitionAction { + /// Transform a `TokenUnfreezeTransition` into a `TokenUnfreezeTransitionAction` 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 `TokenUnfreezeTransition` 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 `TokenUnfreezeTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_token_unfreeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenUnfreezeTransition, + 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 { + TokenUnfreezeTransition::V0(v0) => { + TokenUnfreezeTransitionActionV0::try_from_token_unfreeze_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 `TokenUnfreezeTransition` into a `TokenUnfreezeTransitionAction` 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 `TokenUnfreezeTransition`. + /// * `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 `TokenUnfreezeTransitionAction` if successful, otherwise `ProtocolError`. + pub fn try_from_borrowed_token_unfreeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenUnfreezeTransition, + 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 { + TokenUnfreezeTransition::V0(v0) => { + TokenUnfreezeTransitionActionV0::try_from_borrowed_token_unfreeze_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_unfreeze_transition_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/v0/mod.rs new file mode 100644 index 0000000000..9dab3dfe50 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/v0/mod.rs @@ -0,0 +1,96 @@ +mod transformer; + +use std::sync::Arc; +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 issuance transition action v0 +#[derive(Debug, Clone)] +pub struct TokenUnfreezeTransitionActionV0 { + /// Base token transition action + pub base: TokenBaseTransitionAction, + /// The identity to credit the token to + pub frozen_identity_id: Identifier, + /// A public note + pub public_note: Option, +} + +/// Accessors for `TokenIssuanceTransitionActionV0` +pub trait TokenUnfreezeTransitionActionAccessorsV0 { + /// 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; + + /// Consumes self and returns the identity balance holder ID + fn frozen_identity_id(&self) -> Identifier; + + /// Sets the identity balance holder ID + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier); + + /// Returns the token position in the contract + fn token_position(&self) -> u16 { + 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 TokenUnfreezeTransitionActionAccessorsV0 for TokenUnfreezeTransitionActionV0 { + fn base(&self) -> &TokenBaseTransitionAction { + &self.base + } + + fn base_owned(self) -> TokenBaseTransitionAction { + self.base + } + + fn frozen_identity_id(&self) -> Identifier { + self.frozen_identity_id + } + + fn set_frozen_identity_id(&mut self, frozen_identity_id: Identifier) { + self.frozen_identity_id = frozen_identity_id; + } + + 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_unfreeze_transition_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/v0/transformer.rs new file mode 100644 index 0000000000..b9c2dd5ca8 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/batch/batched_transition/token_transition/token_unfreeze_transition_action/v0/transformer.rs @@ -0,0 +1,232 @@ +use std::sync::Arc; +use grovedb::TransactionArg; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::state_transition::batch_transition::token_unfreeze_transition::v0::TokenUnfreezeTransitionV0; +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_unfreeze_transition_action::v0::TokenUnfreezeTransitionActionV0; +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 TokenUnfreezeTransitionActionV0 { + /// Converts a `TokenUnfreezeTransitionV0` into a `TokenUnfreezeTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token freezeing transition and returns the corresponding transition action + /// while looking up necessary data contracts and applying the relevant logic for freezeing. + /// + /// # Arguments + /// + /// * `drive` - A reference to the `Drive` instance which handles data storage and retrieval. + /// * `owner_id` - The identifier of the owner initiating the freezeing 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 `TokenUnfreezeTransitionV0` 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 `TokenUnfreezeTransitionActionV0` if successful, + /// or an error if any issue arises, such as missing data or an invalid state transition. + pub fn try_from_token_unfreeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: TokenUnfreezeTransitionV0, + 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 TokenUnfreezeTransitionV0 { + base, + frozen_identity_id, + 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::UnfreezeAction( + TokenUnfreezeTransitionActionV0 { + base: base_action, + frozen_identity_id, + public_note, + } + .into(), + )) + .into(), + fee_result, + )) + } + + /// Converts a borrowed `TokenUnfreezeTransitionV0` into a `TokenUnfreezeTransitionActionV0` using the provided contract lookup. + /// + /// This method processes the token freezeing transition and constructs the corresponding transition action while + /// looking up necessary data contracts and applying the relevant freezeing 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 freezeing transition. This is typically the identity + /// performing the transaction, such as the user's ID. + /// * `value` - A reference to the `TokenUnfreezeTransitionV0` 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 + /// `TokenUnfreezeTransitionActionV0` 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_unfreeze_transition_with_contract_lookup( + drive: &Drive, + owner_id: Identifier, + value: &TokenUnfreezeTransitionV0, + 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 TokenUnfreezeTransitionV0 { + base, + frozen_identity_id, + 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::UnfreezeAction( + TokenUnfreezeTransitionActionV0 { + base: base_action, + frozen_identity_id: *frozen_identity_id, + public_note: public_note.clone(), + } + .into(), + )) + .into(), + fee_result, + )) + } +} diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs b/packages/rs-drive/src/state_transition_action/batch/mod.rs similarity index 60% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/mod.rs index 9d5891f0d1..5aad18441e 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/mod.rs @@ -1,5 +1,5 @@ -use crate::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; -use crate::state_transition_action::document::documents_batch::v0::DocumentsBatchTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::v0::BatchTransitionActionV0; use derive_more::From; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; @@ -8,83 +8,83 @@ use dpp::identity::SecurityLevel; use dpp::platform_value::Identifier; use dpp::prelude::UserFeeIncrease; use dpp::ProtocolError; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionAccessorsV0; -/// document transition -pub mod document_transition; +/// batched transition +pub mod batched_transition; /// v0 pub mod v0; /// documents batch transition action #[derive(Debug, Clone, From)] -pub enum DocumentsBatchTransitionAction { +pub enum BatchTransitionAction { /// v0 - V0(DocumentsBatchTransitionActionV0), + V0(BatchTransitionActionV0), } -impl DocumentsBatchTransitionAction { +impl BatchTransitionAction { /// owner id pub fn owner_id(&self) -> Identifier { match self { - DocumentsBatchTransitionAction::V0(v0) => v0.owner_id, + BatchTransitionAction::V0(v0) => v0.owner_id, } } /// transitions - pub fn transitions(&self) -> &Vec { + pub fn transitions(&self) -> &Vec { match self { - DocumentsBatchTransitionAction::V0(v0) => &v0.transitions, + BatchTransitionAction::V0(v0) => &v0.transitions, } } /// transitions - pub fn transitions_mut(&mut self) -> &mut Vec { + pub fn transitions_mut(&mut self) -> &mut Vec { match self { - DocumentsBatchTransitionAction::V0(v0) => &mut v0.transitions, + BatchTransitionAction::V0(v0) => &mut v0.transitions, } } /// transitions - pub fn transitions_take(&mut self) -> Vec { + pub fn transitions_take(&mut self) -> Vec { match self { - DocumentsBatchTransitionAction::V0(v0) => std::mem::take(&mut v0.transitions), + BatchTransitionAction::V0(v0) => std::mem::take(&mut v0.transitions), } } /// transitions owned - pub fn transitions_owned(self) -> Vec { + pub fn transitions_owned(self) -> Vec { match self { - DocumentsBatchTransitionAction::V0(v0) => v0.transitions, + BatchTransitionAction::V0(v0) => v0.transitions, } } /// set transitions - pub fn set_transitions(&mut self, transitions: Vec) { + pub fn set_transitions(&mut self, transitions: Vec) { match self { - DocumentsBatchTransitionAction::V0(v0) => v0.transitions = transitions, + BatchTransitionAction::V0(v0) => v0.transitions = transitions, } } /// fee multiplier pub fn user_fee_increase(&self) -> UserFeeIncrease { match self { - DocumentsBatchTransitionAction::V0(transition) => transition.user_fee_increase, + BatchTransitionAction::V0(transition) => transition.user_fee_increase, } } } -impl DocumentsBatchTransitionAction { +impl BatchTransitionAction { /// The sum of all purchases amount and all conflicting index collateral voting funds pub fn all_used_balances(&self) -> Result, ProtocolError> { match self { - DocumentsBatchTransitionAction::V0(v0) => v0.all_used_balances(), + BatchTransitionAction::V0(v0) => v0.all_used_balances(), } } /// The sum of all purchases amounts for all purchase transitions in the batch pub fn all_purchases_amount(&self) -> Result, ProtocolError> { match self { - DocumentsBatchTransitionAction::V0(v0) => v0.all_purchases_amount(), + BatchTransitionAction::V0(v0) => v0.all_purchases_amount(), } } @@ -93,9 +93,7 @@ impl DocumentsBatchTransitionAction { &self, ) -> Result, ProtocolError> { match self { - DocumentsBatchTransitionAction::V0(v0) => { - v0.all_conflicting_index_collateral_voting_funds() - } + BatchTransitionAction::V0(v0) => v0.all_conflicting_index_collateral_voting_funds(), } } @@ -136,28 +134,20 @@ impl DocumentsBatchTransitionAction { let mut highest_security_level = SecurityLevel::lowest_level(); for transition in self.transitions().iter() { - let document_type_name = transition - .base() - .ok_or(ProtocolError::CorruptedCodeExecution( - "expecting action to have a base".to_string(), - ))? - .document_type_name(); - let data_contract_info = transition - .base() - .ok_or(ProtocolError::CorruptedCodeExecution( - "expecting action to have a base".to_string(), - ))? - .data_contract_fetch_info(); - - let document_type = data_contract_info - .contract - .document_type_for_name(document_type_name)?; - - let document_security_level = document_type.security_level_requirement(); - - // lower enum enum representation means higher in security - if document_security_level < highest_security_level { - highest_security_level = document_security_level + if let BatchedTransitionAction::DocumentAction(document_transition) = transition { + let document_type_name = document_transition.base().document_type_name(); + let data_contract_info = document_transition.base().data_contract_fetch_info(); + + let document_type = data_contract_info + .contract + .document_type_for_name(document_type_name)?; + + let document_security_level = document_type.security_level_requirement(); + + // lower enum enum representation means higher in security + if document_security_level < highest_security_level { + highest_security_level = document_security_level + } } } Ok(if highest_security_level == SecurityLevel::MASTER { diff --git a/packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs b/packages/rs-drive/src/state_transition_action/batch/v0/mod.rs similarity index 68% rename from packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs rename to packages/rs-drive/src/state_transition_action/batch/v0/mod.rs index 295f0c45b4..380fba6af7 100644 --- a/packages/rs-drive/src/state_transition_action/document/documents_batch/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/batch/v0/mod.rs @@ -1,24 +1,27 @@ use dpp::fee::Credits; -use crate::state_transition_action::document::documents_batch::document_transition::DocumentTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::DocumentTransitionAction; use dpp::identifier::Identifier; use dpp::prelude::UserFeeIncrease; use dpp::ProtocolError; -use crate::state_transition_action::document::documents_batch::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_create_transition_action::DocumentCreateTransitionActionAccessorsV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_purchase_transition_action::DocumentPurchaseTransitionActionAccessorsV0; /// action v0 #[derive(Default, Debug, Clone)] -pub struct DocumentsBatchTransitionActionV0 { +pub struct BatchTransitionActionV0 { /// The owner making the transitions pub owner_id: Identifier, /// The inner transitions - pub transitions: Vec, + pub transitions: Vec, /// fee multiplier pub user_fee_increase: UserFeeIncrease, } -impl DocumentsBatchTransitionActionV0 { - pub(super) fn all_used_balances(&self) -> Result, ProtocolError> { +impl BatchTransitionActionV0 { + pub(in crate::state_transition_action) fn all_used_balances( + &self, + ) -> Result, ProtocolError> { Ok(match (self.all_purchases_amount()?, self.all_conflicting_index_collateral_voting_funds()?) { (Some(all_purchases_amount), Some(all_conflicting_index_collateral_voting_funds)) => Some(all_purchases_amount.checked_add(all_conflicting_index_collateral_voting_funds).ok_or(ProtocolError::Overflow("overflow between all_purchases_amount and all_conflicting_index_collateral_voting_funds"))?), (Some(all_purchases_amount), None) => Some(all_purchases_amount), @@ -26,12 +29,16 @@ impl DocumentsBatchTransitionActionV0 { (None, None) => None, }) } - pub(super) fn all_purchases_amount(&self) -> Result, ProtocolError> { + pub(in crate::state_transition_action) fn all_purchases_amount( + &self, + ) -> Result, ProtocolError> { let (total, any_purchases): (Option, bool) = self .transitions .iter() .filter_map(|transition| match transition { - DocumentTransitionAction::PurchaseAction(purchase) => Some(purchase.price()), + BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::PurchaseAction(purchase), + ) => Some(purchase.price()), _ => None, }) .fold((None, false), |(acc, _), price| match acc { @@ -48,19 +55,19 @@ impl DocumentsBatchTransitionActionV0 { } } - pub(super) fn all_conflicting_index_collateral_voting_funds( + pub(in crate::state_transition_action) fn all_conflicting_index_collateral_voting_funds( &self, ) -> Result, ProtocolError> { let (total, any_voting_funds): (Option, bool) = self .transitions .iter() .filter_map(|transition| match transition { - DocumentTransitionAction::CreateAction(document_create_transition_action) => { - document_create_transition_action - .prefunded_voting_balance() - .iter() - .try_fold(0u64, |acc, &(_, val)| acc.checked_add(val)) - } + BatchedTransitionAction::DocumentAction( + DocumentTransitionAction::CreateAction(document_create_transition_action), + ) => document_create_transition_action + .prefunded_voting_balance() + .iter() + .try_fold(0u64, |acc, &(_, val)| acc.checked_add(val)), _ => None, }) .fold((None, false), |(acc, _), price| match acc { diff --git a/packages/rs-drive/src/state_transition_action/document/mod.rs b/packages/rs-drive/src/state_transition_action/document/mod.rs deleted file mode 100644 index 1af2727c64..0000000000 --- a/packages/rs-drive/src/state_transition_action/document/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -/// documents_batch -pub mod documents_batch; diff --git a/packages/rs-drive/src/state_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/mod.rs index c4e9d8477c..13600ca2cc 100644 --- a/packages/rs-drive/src/state_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/mod.rs @@ -1,7 +1,5 @@ /// contract pub mod contract; -/// documents -pub mod document; /// identity pub mod identity; @@ -9,10 +7,12 @@ pub mod identity; pub mod system; // TODO: Must crate only but we need to remove of use it first pub mod action_convert_to_operations; +/// documents_batch +pub mod batch; +use crate::state_transition_action::batch::BatchTransitionAction; use crate::state_transition_action::contract::data_contract_create::DataContractCreateTransitionAction; use crate::state_transition_action::contract::data_contract_update::DataContractUpdateTransitionAction; -use crate::state_transition_action::document::documents_batch::DocumentsBatchTransitionAction; use crate::state_transition_action::identity::identity_create::IdentityCreateTransitionAction; use crate::state_transition_action::identity::identity_credit_transfer::IdentityCreditTransferTransitionAction; use crate::state_transition_action::identity::identity_credit_withdrawal::IdentityCreditWithdrawalTransitionAction; @@ -38,8 +38,8 @@ pub enum StateTransitionAction { DataContractCreateAction(DataContractCreateTransitionAction), /// data contract update DataContractUpdateAction(DataContractUpdateTransitionAction), - /// documents batch - DocumentsBatchAction(DocumentsBatchTransitionAction), + /// batch + BatchAction(BatchTransitionAction), /// identity create IdentityCreateAction(IdentityCreateTransitionAction), /// identity topup @@ -71,7 +71,7 @@ impl StateTransitionAction { match self { StateTransitionAction::DataContractCreateAction(action) => action.user_fee_increase(), StateTransitionAction::DataContractUpdateAction(action) => action.user_fee_increase(), - StateTransitionAction::DocumentsBatchAction(action) => action.user_fee_increase(), + StateTransitionAction::BatchAction(action) => action.user_fee_increase(), StateTransitionAction::IdentityCreateAction(action) => action.user_fee_increase(), StateTransitionAction::IdentityTopUpAction(action) => action.user_fee_increase(), StateTransitionAction::IdentityCreditWithdrawalAction(action) => { diff --git a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs index e5c8c19074..e0691b16e6 100644 --- a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/transformer.rs @@ -1,13 +1,100 @@ use dpp::platform_value::Identifier; use dpp::prelude::UserFeeIncrease; - +use dpp::ProtocolError; +use dpp::state_transition::batch_transition::batched_transition::BatchedTransitionRef; +use dpp::state_transition::batch_transition::batched_transition::document_transition::DocumentTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::token_transition::TokenTransitionV0Methods; use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition; -use dpp::state_transition::documents_batch_transition::document_base_transition::DocumentBaseTransition; +use dpp::state_transition::batch_transition::document_base_transition::DocumentBaseTransition; +use dpp::state_transition::batch_transition::token_base_transition::TokenBaseTransition; +use crate::error::Error; +use crate::state_transition_action::batch::batched_transition::BatchedTransitionAction; use crate::state_transition_action::contract::data_contract_update::DataContractUpdateTransitionAction; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionAction; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionAction; use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::{BumpIdentityDataContractNonceAction, BumpIdentityDataContractNonceActionV0}; impl BumpIdentityDataContractNonceAction { + /// from borrowed base transition + pub fn from_batched_transition_ref( + value: BatchedTransitionRef, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + match value { + BatchedTransitionRef::Document(document) => { + Self::from_borrowed_document_base_transition( + document.base(), + identity_id, + user_fee_increase, + ) + } + BatchedTransitionRef::Token(token) => Self::from_borrowed_token_base_transition( + token.base(), + identity_id, + user_fee_increase, + ), + } + } + + /// helper method + pub fn try_from_batched_transition_action( + value: BatchedTransitionAction, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Result { + match value { + BatchedTransitionAction::DocumentAction(document) => { + Ok(Self::from_document_base_transition_action( + document.base_owned(), + identity_id, + user_fee_increase, + )) + } + BatchedTransitionAction::TokenAction(token) => Ok(Self::from_token_base_transition_action( + token.base_owned(), + identity_id, + user_fee_increase, + )), + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { + Err(Error::Protocol( + ProtocolError::CorruptedCodeExecution( + "we should never be trying to convert from a BumpIdentityDataContractNonce to a BumpIdentityDataContractNonceAction".to_string(), + ), + )) + } + } + } + + /// helper method + pub fn try_from_borrowed_batched_transition_action( + value: &BatchedTransitionAction, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Result { + match value { + BatchedTransitionAction::DocumentAction(document) => { + Ok(Self::from_borrowed_document_base_transition_action( + document.base(), + identity_id, + user_fee_increase, + )) + } + BatchedTransitionAction::TokenAction(token) => Ok(Self::from_borrowed_token_base_transition_action( + token.base(), + identity_id, + user_fee_increase, + )), + BatchedTransitionAction::BumpIdentityDataContractNonce(_) => { + Err(Error::Protocol( + ProtocolError::CorruptedCodeExecution( + "we should never be trying to convert from a BumpIdentityDataContractNonce to a BumpIdentityDataContractNonceAction".to_string(), + ), + )) + } + } + } + /// from base transition pub fn from_document_base_transition( value: DocumentBaseTransition, @@ -16,7 +103,7 @@ impl BumpIdentityDataContractNonceAction { ) -> Self { match value { DocumentBaseTransition::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_base_transition( + BumpIdentityDataContractNonceActionV0::from_document_base_transition( v0, identity_id, user_fee_increase, @@ -34,7 +121,7 @@ impl BumpIdentityDataContractNonceAction { ) -> Self { match value { DocumentBaseTransition::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_borrowed_base_transition( + BumpIdentityDataContractNonceActionV0::from_borrowed_document_base_transition( v0, identity_id, user_fee_increase, @@ -52,7 +139,7 @@ impl BumpIdentityDataContractNonceAction { ) -> Self { match value { DocumentBaseTransitionAction::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_base_transition_action( + BumpIdentityDataContractNonceActionV0::from_document_base_transition_action( v0, identity_id, user_fee_increase, @@ -70,7 +157,79 @@ impl BumpIdentityDataContractNonceAction { ) -> Self { match value { DocumentBaseTransitionAction::V0(v0) => { - BumpIdentityDataContractNonceActionV0::from_borrowed_base_transition_action( + BumpIdentityDataContractNonceActionV0::from_borrowed_document_base_transition_action( + v0, + identity_id, + user_fee_increase, + ) + .into() + } + } + } + + /// from base transition + pub fn from_token_base_transition( + value: TokenBaseTransition, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + match value { + TokenBaseTransition::V0(v0) => { + BumpIdentityDataContractNonceActionV0::from_token_base_transition( + v0, + identity_id, + user_fee_increase, + ) + .into() + } + } + } + + /// from borrowed base transition + pub fn from_borrowed_token_base_transition( + value: &TokenBaseTransition, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + match value { + TokenBaseTransition::V0(v0) => { + BumpIdentityDataContractNonceActionV0::from_borrowed_token_base_transition( + v0, + identity_id, + user_fee_increase, + ) + .into() + } + } + } + + /// from base transition + pub fn from_token_base_transition_action( + value: TokenBaseTransitionAction, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + match value { + TokenBaseTransitionAction::V0(v0) => { + BumpIdentityDataContractNonceActionV0::from_token_base_transition_action( + v0, + identity_id, + user_fee_increase, + ) + .into() + } + } + } + + /// from borrowed base transition + pub fn from_borrowed_token_base_transition_action( + value: &TokenBaseTransitionAction, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + match value { + TokenBaseTransitionAction::V0(v0) => { + BumpIdentityDataContractNonceActionV0::from_borrowed_token_base_transition_action( v0, identity_id, user_fee_increase, diff --git a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs index 42a9912790..c87a865a70 100644 --- a/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/system/bump_identity_data_contract_nonce_action/v0/transformer.rs @@ -3,14 +3,16 @@ use dpp::platform_value::Identifier; use dpp::prelude::UserFeeIncrease; use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransitionV0; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dpp::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dpp::state_transition::batch_transition::token_base_transition::v0::TokenBaseTransitionV0; use crate::state_transition_action::contract::data_contract_update::v0::DataContractUpdateTransitionActionV0; -use crate::state_transition_action::document::documents_batch::document_transition::document_base_transition_action::DocumentBaseTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::document_transition::document_base_transition_action::DocumentBaseTransitionActionV0; +use crate::state_transition_action::batch::batched_transition::token_transition::token_base_transition_action::TokenBaseTransitionActionV0; use crate::state_transition_action::system::bump_identity_data_contract_nonce_action::BumpIdentityDataContractNonceActionV0; impl BumpIdentityDataContractNonceActionV0 { /// from base transition - pub fn from_base_transition( + pub fn from_document_base_transition( value: DocumentBaseTransitionV0, identity_id: Identifier, user_fee_increase: UserFeeIncrease, @@ -29,7 +31,7 @@ impl BumpIdentityDataContractNonceActionV0 { } /// from borrowed base transition - pub fn from_borrowed_base_transition( + pub fn from_borrowed_document_base_transition( value: &DocumentBaseTransitionV0, identity_id: Identifier, user_fee_increase: UserFeeIncrease, @@ -48,7 +50,7 @@ impl BumpIdentityDataContractNonceActionV0 { } /// from base transition - pub fn from_base_transition_action( + pub fn from_document_base_transition_action( value: DocumentBaseTransitionActionV0, identity_id: Identifier, user_fee_increase: UserFeeIncrease, @@ -67,7 +69,7 @@ impl BumpIdentityDataContractNonceActionV0 { } /// from borrowed base transition - pub fn from_borrowed_base_transition_action( + pub fn from_borrowed_document_base_transition_action( value: &DocumentBaseTransitionActionV0, identity_id: Identifier, user_fee_increase: UserFeeIncrease, @@ -85,6 +87,82 @@ impl BumpIdentityDataContractNonceActionV0 { } } + /// from base transition + pub fn from_token_base_transition( + value: TokenBaseTransitionV0, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + let TokenBaseTransitionV0 { + data_contract_id, + identity_contract_nonce, + .. + } = value; + BumpIdentityDataContractNonceActionV0 { + identity_id, + data_contract_id, + identity_contract_nonce, + user_fee_increase, + } + } + + /// from borrowed base transition + pub fn from_borrowed_token_base_transition( + value: &TokenBaseTransitionV0, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + let TokenBaseTransitionV0 { + data_contract_id, + identity_contract_nonce, + .. + } = value; + BumpIdentityDataContractNonceActionV0 { + identity_id, + data_contract_id: *data_contract_id, + identity_contract_nonce: *identity_contract_nonce, + user_fee_increase, + } + } + + /// from base transition + pub fn from_token_base_transition_action( + value: TokenBaseTransitionActionV0, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + let TokenBaseTransitionActionV0 { + data_contract, + identity_contract_nonce, + .. + } = value; + BumpIdentityDataContractNonceActionV0 { + identity_id, + data_contract_id: data_contract.contract.id(), + identity_contract_nonce, + user_fee_increase, + } + } + + /// from borrowed base transition + pub fn from_borrowed_token_base_transition_action( + value: &TokenBaseTransitionActionV0, + identity_id: Identifier, + user_fee_increase: UserFeeIncrease, + ) -> Self { + let TokenBaseTransitionActionV0 { + data_contract, + identity_contract_nonce, + .. + } = value; + BumpIdentityDataContractNonceActionV0 { + identity_id, + data_contract_id: data_contract.contract.id(), + identity_contract_nonce: *identity_contract_nonce, + user_fee_increase, + } + } + /// from data contract update pub fn from_data_contract_update(value: DataContractUpdateTransitionV0) -> Self { let DataContractUpdateTransitionV0 { diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/convert_drive_operations_to_grove_operations/v0/mod.rs b/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/convert_drive_operations_to_grove_operations/v0/mod.rs index de4fecc4c4..0b719f85d4 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/convert_drive_operations_to_grove_operations/v0/mod.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/convert_drive_operations_to_grove_operations/v0/mod.rs @@ -30,7 +30,7 @@ impl Drive { /// Returns a `Result` containing a `GroveDbOpBatch` with transformed grove database operations, /// or an error if any step in the conversion process fails. #[inline(always)] - pub(crate) fn convert_drive_operations_to_grove_operations_v0( + pub(super) fn convert_drive_operations_to_grove_operations_v0( &self, drive_batch_operations: Vec, block_info: &BlockInfo, diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/group.rs b/packages/rs-drive/src/util/batch/drive_op_batch/group.rs new file mode 100644 index 0000000000..ce1a193c45 --- /dev/null +++ b/packages/rs-drive/src/util/batch/drive_op_batch/group.rs @@ -0,0 +1,68 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::batch::drive_op_batch::DriveLowLevelOperationConverter; +use dpp::block::block_info::BlockInfo; +use dpp::data_contract::group::GroupMemberPower; +use dpp::data_contract::GroupContractPosition; +use dpp::group::group_action::GroupAction; +use dpp::identifier::Identifier; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +/// Group operations requiring many people to agree to something for the action to occur. +#[derive(Clone, Debug)] +pub enum GroupOperationType { + /// Adds a group action + AddGroupAction { + /// The contract id + contract_id: Identifier, + /// The group contract position + group_contract_position: GroupContractPosition, + /// Initialize with the action info + initialize_with_insert_action_info: Option, + /// The action id + action_id: Identifier, + /// The identity that is signing + signer_identity_id: Identifier, + /// The signer's power in the group + signer_power: GroupMemberPower, + }, +} + +impl DriveLowLevelOperationConverter for GroupOperationType { + fn into_low_level_drive_operations( + self, + drive: &Drive, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match self { + GroupOperationType::AddGroupAction { + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + } => drive.add_group_action_operations( + contract_id, + group_contract_position, + initialize_with_insert_action_info, + action_id, + signer_identity_id, + signer_power, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + } + } +} diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs index abdd9f4cc6..8ccfc48578 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs @@ -2,9 +2,11 @@ mod contract; mod document; mod drive_methods; mod finalize_task; +mod group; mod identity; mod prefunded_specialized_balance; mod system; +mod token; mod withdrawals; use crate::util::batch::GroveDbOpBatch; @@ -19,9 +21,11 @@ pub use document::DocumentOperation; pub use document::DocumentOperationType; pub use document::DocumentOperationsForContractDocumentType; pub use document::UpdateOperationInfo; +pub use group::GroupOperationType; pub use identity::IdentityOperationType; pub use prefunded_specialized_balance::PrefundedSpecializedBalanceOperationType; pub use system::SystemOperationType; +pub use token::TokenOperationType; pub use withdrawals::WithdrawalOperationType; use grovedb::{EstimatedLayerInformation, TransactionArg}; @@ -69,6 +73,8 @@ pub enum DriveOperation<'a> { DataContractOperation(DataContractOperationType<'a>), /// A document operation DocumentOperation(DocumentOperationType<'a>), + /// A token operation + TokenOperation(TokenOperationType), /// Withdrawal operation WithdrawalOperation(WithdrawalOperationType), /// An identity operation @@ -77,6 +83,8 @@ pub enum DriveOperation<'a> { PrefundedSpecializedBalanceOperation(PrefundedSpecializedBalanceOperationType), /// A system operation SystemOperation(SystemOperationType), + /// A group operation + GroupOperation(GroupOperationType), /// A single low level groveDB operation GroveDBOperation(QualifiedGroveDbOp), /// Multiple low level groveDB operations @@ -152,6 +160,22 @@ impl DriveLowLevelOperationConverter for DriveOperation<'_> { .into_iter() .map(GroveOperation) .collect()), + DriveOperation::TokenOperation(token_operation_type) => token_operation_type + .into_low_level_drive_operations( + drive, + estimated_costs_only_with_layer_info, + block_info, + transaction, + platform_version, + ), + DriveOperation::GroupOperation(group_operation_type) => group_operation_type + .into_low_level_drive_operations( + drive, + estimated_costs_only_with_layer_info, + block_info, + transaction, + platform_version, + ), } } } @@ -199,16 +223,16 @@ mod tests { use super::*; + use crate::util::test_helpers::setup_contract; use dpp::block::block_info::BlockInfo; use dpp::data_contract::accessors::v0::DataContractV0Getters; + use dpp::data_contract::DataContract; use dpp::serialization::PlatformSerializableWithPlatformVersion; use dpp::tests::json_document::{json_document_to_contract, json_document_to_document}; use dpp::util::cbor_serializer; use rand::Rng; use serde_json::json; - use crate::util::test_helpers::setup_contract; - use crate::util::batch::drive_op_batch::document::DocumentOperation::{ AddOperation, UpdateOperation, }; @@ -579,7 +603,10 @@ mod tests { &drive, "tests/supporting_files/contract/family/family-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -690,7 +717,10 @@ mod tests { &drive, "tests/supporting_files/contract/family/family-contract-only-age-index.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract @@ -907,7 +937,10 @@ mod tests { &drive, "tests/supporting_files/contract/family/family-contract-only-age-index.json", None, + None, + None::, Some(&db_transaction), + None, ); let document_type = contract 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 new file mode 100644 index 0000000000..51b976c4dc --- /dev/null +++ b/packages/rs-drive/src/util/batch/drive_op_batch/token.rs @@ -0,0 +1,212 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::batch::drive_op_batch::DriveLowLevelOperationConverter; +use dpp::balances::credits::TokenAmount; +use dpp::block::block_info::BlockInfo; +use dpp::identifier::Identifier; +use dpp::prelude::IdentityNonce; +use dpp::tokens::status::TokenStatus; +use dpp::tokens::token_event::TokenEvent; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use platform_version::version::PlatformVersion; +use std::collections::HashMap; + +/// Operations on Tokens +#[derive(Clone, Debug)] +pub enum TokenOperationType { + /// Burns token from the account issuing the action. + TokenBurn { + /// The token id + token_id: Identifier, + /// The identity to burn from + identity_balance_holder_id: Identifier, + /// The amount to burn + burn_amount: TokenAmount, + }, + /// Mints tokens + TokenMint { + /// The token id + token_id: Identifier, + /// The identity to burn from + identity_balance_holder_id: Identifier, + /// The amount to issue + mint_amount: TokenAmount, + /// Should we allow this to be the first ever mint + allow_first_mint: bool, + }, + /// Performs a token transfer + TokenTransfer { + /// The token id + token_id: Identifier, + /// The token id + sender_id: Identifier, + /// The recipient of the transfer + recipient_id: Identifier, + /// The amount to transfer + amount: TokenAmount, + }, + /// Freezes an identity's token balance so money can no longer be sent out. + TokenFreeze { + /// The token id + token_id: Identifier, + /// The frozen identity id + frozen_identity_id: Identifier, + }, + /// Unfreezes an identity's token balance so money can be sent out again. + TokenUnfreeze { + /// The token id + token_id: Identifier, + /// The frozen identity id + frozen_identity_id: Identifier, + }, + /// Sets the status of the token. + TokenSetStatus { + /// The token id + token_id: Identifier, + /// The status + status: TokenStatus, + }, + /// Adds a historical document explaining a token action. + TokenHistory { + /// The token id + token_id: Identifier, + /// The identity making the event + owner_id: Identifier, + /// The nonce + nonce: IdentityNonce, + /// The token event + event: TokenEvent, + }, +} + +impl DriveLowLevelOperationConverter for TokenOperationType { + fn into_low_level_drive_operations( + self, + drive: &Drive, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match self { + TokenOperationType::TokenBurn { + token_id, + identity_balance_holder_id, + burn_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_burn_operations( + token_id_bytes, + identity_id_bytes, + burn_amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + Ok(batch_operations) + } + TokenOperationType::TokenMint { + token_id, + identity_balance_holder_id, + 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( + token_id_bytes, + identity_id_bytes, + mint_amount, + allow_first_mint, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + Ok(batch_operations) + } + TokenOperationType::TokenTransfer { + token_id, + sender_id, + recipient_id, + amount, + } => { + let token_id_bytes: [u8; 32] = token_id.to_buffer(); + let sender_id_bytes: [u8; 32] = sender_id.to_buffer(); + let recipient_id_bytes: [u8; 32] = recipient_id.to_buffer(); + + let batch_operations = drive.token_transfer_operations( + token_id_bytes, + sender_id_bytes, + recipient_id_bytes, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + Ok(batch_operations) + } + TokenOperationType::TokenHistory { + token_id, + owner_id, + nonce, + event, + } => { + let batch_operations = drive.add_token_transaction_history_operations( + token_id, + owner_id, + nonce, + event, + block_info, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + Ok(batch_operations) + } + TokenOperationType::TokenFreeze { + token_id, + frozen_identity_id, + } => { + let batch_operations = drive.token_freeze_operations( + token_id, + frozen_identity_id, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + Ok(batch_operations) + } + TokenOperationType::TokenUnfreeze { + token_id, + frozen_identity_id, + } => { + let batch_operations = drive.token_unfreeze_operations( + token_id, + frozen_identity_id, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + )?; + Ok(batch_operations) + } + TokenOperationType::TokenSetStatus { token_id, status } => { + let batch_operations = drive.token_apply_status_operations( + token_id.to_buffer(), + status, + estimated_costs_only_with_layer_info, + platform_version, + )?; + Ok(batch_operations) + } + } + } +} diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs b/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs index 26bf6617a7..8146f534d7 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/withdrawals.rs @@ -18,7 +18,7 @@ use dpp::fee::{Credits, SignedCredits}; use dpp::prelude::TimestampMillis; use dpp::version::PlatformVersion; use dpp::withdrawal::{WithdrawalTransactionIndex, WithdrawalTransactionIndexAndBytes}; -use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, TransactionArg}; +use grovedb::{batch::KeyInfoPath, EstimatedLayerInformation, MaybeTree, TransactionArg}; use grovedb::{Element, PathQuery, SizedQuery}; /// Operations for Withdrawals @@ -164,7 +164,7 @@ impl DriveLowLevelOperationConverter for WithdrawalOperationType { true, // we know that we are not deleting a subtree BatchMoveApplyType::StatefulBatchMove { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, &mut drive_operations, @@ -205,7 +205,7 @@ impl DriveLowLevelOperationConverter for WithdrawalOperationType { true, // we know that we are not deleting a subtree BatchMoveApplyType::StatefulBatchMove { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, &mut drive_operations, @@ -244,7 +244,7 @@ impl DriveLowLevelOperationConverter for WithdrawalOperationType { true, // we know that we are not deleting a subtree BatchDeleteApplyType::StatefulBatchDelete { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }, transaction, &mut drive_operations, diff --git a/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs b/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs index 67d5f8908e..ecf25027e2 100644 --- a/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs +++ b/packages/rs-drive/src/util/batch/grovedb_op_batch/mod.rs @@ -13,7 +13,7 @@ use dpp::prelude::Identifier; use grovedb::batch::key_info::KeyInfo; use grovedb::batch::{GroveDbOpConsistencyResults, GroveOp, KeyInfoPath, QualifiedGroveDbOp}; use grovedb::operations::proof::util::hex_to_ascii; -use grovedb::Element; +use grovedb::{Element, TreeType}; use std::borrow::Cow; use std::fmt; @@ -52,6 +52,7 @@ enum KnownPath { TokenBalancesRoot, //Level 1 VersionsRoot, //Level 1 VotesRoot, //Level 1 + GroupActionsRoot, //Level 1 } impl From for KnownPath { @@ -71,9 +72,10 @@ impl From for KnownPath { RootTree::Misc => KnownPath::MiscRoot, RootTree::WithdrawalTransactions => KnownPath::WithdrawalTransactionsRoot, RootTree::Balances => KnownPath::BalancesRoot, - RootTree::TokenBalances => KnownPath::TokenBalancesRoot, + RootTree::Tokens => KnownPath::TokenBalancesRoot, RootTree::Versions => KnownPath::VersionsRoot, RootTree::Votes => KnownPath::VotesRoot, + RootTree::GroupActions => KnownPath::GroupActionsRoot, } } } @@ -358,7 +360,7 @@ pub trait GroveDbOpBatchV0Methods { fn add_delete(&mut self, path: Vec>, key: Vec); /// Adds a `Delete` tree operation to a list of GroveDB ops. - fn add_delete_tree(&mut self, path: Vec>, key: Vec, is_sum_tree: bool); + fn add_delete_tree(&mut self, path: Vec>, key: Vec, tree_type: TreeType); /// Adds an `Insert` operation with an element to a list of GroveDB ops. fn add_insert(&mut self, path: Vec>, key: Vec, element: Element); @@ -510,9 +512,9 @@ impl GroveDbOpBatchV0Methods for GroveDbOpBatch { } /// Adds a `Delete` tree operation to a list of GroveDB ops. - fn add_delete_tree(&mut self, path: Vec>, key: Vec, is_sum_tree: bool) { + fn add_delete_tree(&mut self, path: Vec>, key: Vec, tree_type: TreeType) { self.operations - .push(QualifiedGroveDbOp::delete_tree_op(path, key, is_sum_tree)) + .push(QualifiedGroveDbOp::delete_tree_op(path, key, tree_type)) } /// Adds an `Insert` operation with an element to a list of GroveDB ops. diff --git a/packages/rs-drive/src/util/grove_operations/batch_delete/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_delete/v0/mod.rs index 25a083ced3..bc77445630 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_delete/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_delete/v0/mod.rs @@ -32,7 +32,7 @@ impl Drive { }; let delete_operation = match apply_type { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_key_size, estimated_value_size, } => GroveDb::average_case_delete_operation_for_delete::( diff --git a/packages/rs-drive/src/util/grove_operations/batch_delete_items_in_path_query/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_delete_items_in_path_query/v0/mod.rs index a530776986..3ae43af7c8 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_delete_items_in_path_query/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_delete_items_in_path_query/v0/mod.rs @@ -87,7 +87,7 @@ impl Drive { }; let delete_operation = match apply_type { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_key_size, estimated_value_size, } => GroveDb::average_case_delete_operation_for_delete::( @@ -136,14 +136,14 @@ mod tests { util::grove_operations::BatchDeleteApplyType, }; use assert_matches::assert_matches; - use grovedb::SizedQuery; + use grovedb::{SizedQuery, TreeType}; use grovedb_path::SubtreePath; use platform_version::version::PlatformVersion; #[test] fn test_batch_delete_items_in_path_query_success() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -234,7 +234,7 @@ mod tests { #[test] fn test_batch_delete_items_in_path_query_range_query() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -379,7 +379,7 @@ mod tests { #[test] fn test_batch_delete_items_in_path_query_no_elements() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -455,7 +455,7 @@ mod tests { #[test] fn test_batch_delete_items_in_path_query_intermediate_path_missing() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -491,7 +491,7 @@ mod tests { #[test] fn test_batch_delete_items_in_path_query_stateless_delete() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -533,7 +533,7 @@ mod tests { // Set up the stateless apply type with estimated sizes let apply_type = BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree: false, + in_tree_type: TreeType::NormalTree, estimated_key_size: key.len() as u32, estimated_value_size: element .serialized_size(&platform_version.drive.grove_version) diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/mod.rs new file mode 100644 index 0000000000..2a2a033ff4 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/mod.rs @@ -0,0 +1,52 @@ +mod v0; + +use crate::util::object_size_info::DriveKeyInfo; +use crate::util::storage_flags::StorageFlags; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::drive_versions::DriveVersion; + +impl Drive { + /// Pushes an "insert empty tree" operation to `drive_operations`. + /// + /// # Parameters + /// * `path`: The path to insert an empty tree. + /// * `key_info`: The key information of the document. + /// * `storage_flags`: Storage options for the operation. + /// * `drive_operations`: The vector containing low-level drive operations. + /// * `drive_version`: The drive version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(())` if the operation was successful. + /// * `Err(DriveError::UnknownVersionMismatch)` if the drive version does not match known versions. + pub fn batch_insert_empty_sum_tree<'a, 'c, P>( + &'a self, + path: P, + key_info: DriveKeyInfo<'c>, + storage_flags: Option<&StorageFlags>, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result<(), Error> + where + P: IntoIterator, +

::IntoIter: ExactSizeIterator + DoubleEndedIterator + Clone, + { + match drive_version + .grove_methods + .batch + .batch_insert_empty_sum_tree + { + 0 => { + self.batch_insert_empty_sum_tree_v0(path, key_info, storage_flags, drive_operations) + } + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "batch_insert_empty_sum_tree".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/v0/mod.rs new file mode 100644 index 0000000000..fb76aa3f18 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_sum_tree/v0/mod.rs @@ -0,0 +1,53 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::object_size_info::DriveKeyInfo; +use crate::util::object_size_info::DriveKeyInfo::{Key, KeyRef, KeySize}; +use crate::util::storage_flags::StorageFlags; +use grovedb::batch::KeyInfoPath; + +impl Drive { + /// Pushes an "insert empty tree" operation to `drive_operations`. + pub(crate) fn batch_insert_empty_sum_tree_v0<'a, 'c, P>( + &'a self, + path: P, + key_info: DriveKeyInfo<'c>, + storage_flags: Option<&StorageFlags>, + drive_operations: &mut Vec, + ) -> Result<(), Error> + where + P: IntoIterator, +

::IntoIter: ExactSizeIterator + DoubleEndedIterator + Clone, + { + match key_info { + KeyRef(key) => { + let path_items: Vec> = path.into_iter().map(Vec::from).collect(); + drive_operations.push(LowLevelDriveOperation::for_known_path_key_empty_sum_tree( + path_items, + key.to_vec(), + storage_flags, + )); + Ok(()) + } + KeySize(key) => { + drive_operations.push( + LowLevelDriveOperation::for_estimated_path_key_empty_sum_tree( + KeyInfoPath::from_known_path(path), + key, + storage_flags, + ), + ); + Ok(()) + } + Key(key) => { + let path_items: Vec> = path.into_iter().map(Vec::from).collect(); + drive_operations.push(LowLevelDriveOperation::for_known_path_key_empty_sum_tree( + path_items, + key, + storage_flags, + )); + Ok(()) + } + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/mod.rs index a4f630e691..5425de9741 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/mod.rs @@ -10,7 +10,7 @@ use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::version::drive_versions::DriveVersion; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Pushes an "insert empty tree where path key does not yet exist" operation to `drive_operations`. @@ -19,7 +19,7 @@ impl Drive { pub fn batch_insert_empty_tree_if_not_exists( &self, path_key_info: PathKeyInfo, - use_sum_tree: bool, + tree_type: TreeType, storage_flags: Option<&StorageFlags>, apply_type: BatchInsertTreeApplyType, transaction: TransactionArg, @@ -34,7 +34,7 @@ impl Drive { { 0 => self.batch_insert_empty_tree_if_not_exists_v0( path_key_info, - use_sum_tree, + tree_type, storage_flags, apply_type, transaction, diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/v0/mod.rs index 4f2c30664c..e1b0dc30b3 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_empty_tree_if_not_exists/v0/mod.rs @@ -1,8 +1,8 @@ use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; -use crate::fees::op::LowLevelDriveOperation; use crate::fees::op::LowLevelDriveOperation::GroveOperation; +use crate::fees::op::{LowLevelDriveOperation, LowLevelDriveOperationTreeTypeConverter}; use crate::util::grove_operations::BatchInsertTreeApplyType; use crate::util::object_size_info::PathKeyInfo; use crate::util::object_size_info::PathKeyInfo::{ @@ -11,7 +11,7 @@ use crate::util::object_size_info::PathKeyInfo::{ use crate::util::storage_flags::StorageFlags; use dpp::version::drive_versions::DriveVersion; use grovedb::batch::GroveOp; -use grovedb::TransactionArg; +use grovedb::{TransactionArg, TreeType}; impl Drive { /// Pushes an "insert empty tree where path key does not yet exist" operation to `drive_operations`. @@ -19,7 +19,7 @@ impl Drive { pub(crate) fn batch_insert_empty_tree_if_not_exists_v0( &self, path_key_info: PathKeyInfo, - use_sum_tree: bool, + tree_type: TreeType, storage_flags: Option<&StorageFlags>, apply_type: BatchInsertTreeApplyType, transaction: TransactionArg, @@ -30,19 +30,11 @@ impl Drive { //todo: clean up the duplication match path_key_info { PathKeyRef((path, key)) => { - let drive_operation = if use_sum_tree { - LowLevelDriveOperation::for_known_path_key_empty_sum_tree( - path.clone(), - key.to_vec(), - storage_flags, - ) - } else { - LowLevelDriveOperation::for_known_path_key_empty_tree( - path.clone(), - key.to_vec(), - storage_flags, - ) - }; + let drive_operation = tree_type.empty_tree_operation_for_known_path_key( + path.clone(), + key.to_vec(), + storage_flags, + ); // we only add the operation if it doesn't already exist in the current batch if let Some(existing_operations) = check_existing_operations { let mut i = 0; @@ -58,7 +50,7 @@ impl Drive { } else if let GroveOperation(grove_op) = previous_drive_operation { if grove_op.key == key && grove_op.path == path - && matches!(grove_op.op, GroveOp::DeleteTree) + && matches!(grove_op.op, GroveOp::DeleteTree(_)) { found = true; existing_operations.remove(i); @@ -105,19 +97,11 @@ impl Drive { DriveError::NotSupportedPrivate("document sizes in batch operations not supported"), )), PathKey((path, key)) => { - let drive_operation = if use_sum_tree { - LowLevelDriveOperation::for_known_path_key_empty_sum_tree( - path.clone(), - key.to_vec(), - storage_flags, - ) - } else { - LowLevelDriveOperation::for_known_path_key_empty_tree( - path.clone(), - key.to_vec(), - storage_flags, - ) - }; + let drive_operation = tree_type.empty_tree_operation_for_known_path_key( + path.clone(), + key.to_vec(), + storage_flags, + ); // we only add the operation if it doesn't already exist in the current batch if let Some(existing_operations) = check_existing_operations { let mut i = 0; @@ -133,7 +117,7 @@ impl Drive { } else if let GroveOperation(grove_op) = previous_drive_operation { if grove_op.key == key && grove_op.path == path - && matches!(grove_op.op, GroveOp::DeleteTree) + && matches!(grove_op.op, GroveOp::DeleteTree(_)) { found = true; existing_operations.remove(i); @@ -178,19 +162,11 @@ impl Drive { } PathFixedSizeKey((path, key)) => { let path_items: Vec> = path.into_iter().map(Vec::from).collect(); - let drive_operation = if use_sum_tree { - LowLevelDriveOperation::for_known_path_key_empty_sum_tree( - path_items, - key.to_vec(), - storage_flags, - ) - } else { - LowLevelDriveOperation::for_known_path_key_empty_tree( - path_items, - key.to_vec(), - storage_flags, - ) - }; + let drive_operation = tree_type.empty_tree_operation_for_known_path_key( + path_items, + key.to_vec(), + storage_flags, + ); // we only add the operation if it doesn't already exist in the current batch if let Some(existing_operations) = check_existing_operations { let mut i = 0; @@ -206,7 +182,7 @@ impl Drive { } else if let GroveOperation(grove_op) = previous_drive_operation { if grove_op.key == key && grove_op.path == path - && matches!(grove_op.op, GroveOp::DeleteTree) + && matches!(grove_op.op, GroveOp::DeleteTree(_)) { found = true; existing_operations.remove(i); @@ -251,19 +227,11 @@ impl Drive { } PathFixedSizeKeyRef((path, key)) => { let path_items: Vec> = path.into_iter().map(Vec::from).collect(); - let drive_operation = if use_sum_tree { - LowLevelDriveOperation::for_known_path_key_empty_sum_tree( - path_items, - key.to_vec(), - storage_flags, - ) - } else { - LowLevelDriveOperation::for_known_path_key_empty_tree( - path_items, - key.to_vec(), - storage_flags, - ) - }; + let drive_operation = tree_type.empty_tree_operation_for_known_path_key( + path_items, + key.to_vec(), + storage_flags, + ); // we only add the operation if it doesn't already exist in the current batch if let Some(existing_operations) = check_existing_operations { let mut i = 0; @@ -279,7 +247,7 @@ impl Drive { } else if let GroveOperation(grove_op) = previous_drive_operation { if grove_op.key == key && grove_op.path == path - && matches!(grove_op.op, GroveOp::DeleteTree) + && matches!(grove_op.op, GroveOp::DeleteTree(_)) { found = true; existing_operations.remove(i); diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_if_changed_value/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_if_changed_value/v0/mod.rs index de5431d8f1..f464fc3c18 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_insert_if_changed_value/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_if_changed_value/v0/mod.rs @@ -99,7 +99,8 @@ impl Drive { PathKeyElementSize((key_info_path, key_info, element)) => { match apply_type { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums, .. + in_tree_type: in_tree_using_sums, + .. } => { // we can estimate that the element was the same size drive_operations.push(CalculatedCostOperation( diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists/v0/mod.rs index 8fc5c16c5b..cdf15dc489 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists/v0/mod.rs @@ -87,7 +87,8 @@ impl Drive { PathKeyElementSize((key_info_path, key_info, element)) => { match apply_type { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums, .. + in_tree_type: in_tree_using_sums, + .. } => { // we can estimate that the element was the same size drive_operations.push(CalculatedCostOperation( diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists_return_existing_element/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists_return_existing_element/v0/mod.rs index 55f411caeb..ed3e356880 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists_return_existing_element/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_if_not_exists_return_existing_element/v0/mod.rs @@ -129,7 +129,8 @@ impl Drive { PathKeyElementSize((key_info_path, key_info, element)) => { match apply_type { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums, .. + in_tree_type: in_tree_using_sums, + .. } => { // Estimate if the element with the given size already exists drive_operations.push(CalculatedCostOperation( diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs new file mode 100644 index 0000000000..9200949046 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/mod.rs @@ -0,0 +1,71 @@ +mod v0; + +use crate::util::grove_operations::BatchInsertApplyType; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::object_size_info::PathKeyElementInfo; + +use dpp::version::drive_versions::DriveVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Attempts to batch insert a sum item at the specified path and key if it doesn't already exist. + /// This method dispatches to the appropriate version of the `batch_insert_sum_item_if_not_exists` function + /// based on the version of the drive. Currently, version `0` is supported. + /// + /// # Parameters + /// * `path_key_element_info`: Contains the path, key, and element information to be inserted. + /// * `error_if_exists`: A flag that determines whether an error is returned if a sum item already exists at the given path and key. + /// * `apply_type`: Defines the batch insert type, such as stateless or stateful insertion. + /// * `transaction`: The transaction argument used for the operation. + /// * `drive_operations`: A mutable reference to a vector that collects low-level drive operations to be executed. + /// * `drive_version`: The version of the drive that influences the behavior of the batch insert operation. + /// + /// # Returns + /// * `Ok(())` if the batch insert is successful. + /// * `Err(Error)` if the operation fails, including an error for unknown version mismatches. + /// + /// # Description + /// This function checks the version of the drive's batch methods and dispatches the operation to the appropriate version of + /// `batch_insert_sum_item_if_not_exists`. Currently, only version `0` is supported, which delegates to the function + /// `batch_insert_sum_item_if_not_exists_v0`. If the drive version is not supported, an error is returned. + /// + /// In version `0`, the function performs the following: + /// - Checks if a sum item exists at the specified path and key. + /// - If the sum item exists and `error_if_exists` is true, an error is returned. + /// - If no sum item exists, a new sum item is inserted at the path and key. + /// + /// This method allows flexibility for future versions of the drive to implement different behaviors for batch insertion. + pub fn batch_insert_sum_item_if_not_exists( + &self, + path_key_element_info: PathKeyElementInfo, + error_if_exists: bool, + apply_type: BatchInsertApplyType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result { + match drive_version + .grove_methods + .batch + .batch_insert_sum_item_if_not_exists + { + 0 => self.batch_insert_sum_item_if_not_exists_v0( + path_key_element_info, + error_if_exists, + apply_type, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "batch_insert_sum_item_if_not_exists".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs new file mode 100644 index 0000000000..902f806e79 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_if_not_exists/v0/mod.rs @@ -0,0 +1,230 @@ +use crate::util::grove_operations::BatchInsertApplyType; +use crate::util::object_size_info::PathKeyElementInfo::{ + PathFixedSizeKeyRefElement, PathKeyElement, PathKeyElementSize, PathKeyRefElement, + PathKeyUnknownElementSize, +}; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use crate::util::object_size_info::PathKeyElementInfo; +use dpp::version::drive_versions::DriveVersion; +use grovedb::{Element, GroveDb, TransactionArg}; + +impl Drive { + /// Inserts a sum item at the specified path and key if it doesn't already exist. + /// If a sum item exists at the specified location and `error_if_exists` is true, an error is returned. + /// If a sum item exists and `error_if_exists` is false, no changes are made. + /// If no sum item exists, a new sum item is inserted at the specified path and key. + /// + /// # Parameters + /// * `path_key_element_info`: Contains information about the path, key, and element to be processed. + /// * `error_if_exists`: A flag that determines whether to return an error if the sum item already exists. + /// * `apply_type`: Defines the type of batch insert to be performed (stateful or stateless). + /// * `transaction`: The transaction argument for the operation. + /// * `drive_operations`: A mutable reference to a vector of low-level drive operations to which new operations will be appended. + /// * `drive_version`: The version of the drive to ensure compatibility with the operation. + /// + /// # Returns + /// * `Ok(())` if the operation is successful. + /// * `Err(Error)` if the operation fails for any reason, such as corrupted state or unsupported operation. + /// + /// # Description + /// This function checks whether an existing sum item exists at the given path and key: + /// - If a sum item is found and `error_if_exists` is true, an error is returned. + /// - If a sum item is found and `error_if_exists` is false, no changes are made. + /// - If no sum item exists, a new sum item is inserted at the specified path and key. + /// + /// This function supports several types of paths and keys, including: + /// - `PathKeyRefElement`: A path with a reference to a key and element. + /// - `PathKeyElement`: A path with a direct key and element. + /// - `PathFixedSizeKeyRefElement`: A fixed-size key reference. + /// - `PathKeyElementSize`: An element with an associated size. + /// - `PathKeyUnknownElementSize`: An unknown element size type. + /// + /// Depending on the element type (`SumItem` in this case), the appropriate operations will be applied. + /// + /// **Note**: Stateful batch insertions of document sizes are not supported. + pub(super) fn batch_insert_sum_item_if_not_exists_v0( + &self, + path_key_element_info: PathKeyElementInfo, + error_if_exists: bool, + apply_type: BatchInsertApplyType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result { + match path_key_element_info { + PathKeyRefElement((path, key, element)) => { + if let Element::SumItem(new_value, _) = element { + // Check if the sum item already exists + let existing_element = self.grove_get_raw_optional( + path.as_slice().into(), + key, + apply_type.to_direct_query_type(), + transaction, + drive_operations, + drive_version, + )?; + + if let Some(Element::SumItem(..)) = existing_element { + return if error_if_exists { + Err(Error::Drive(DriveError::CorruptedDriveState( + "expected no sum item".to_string(), + ))) + } else { + Ok(false) + }; + // Else do nothing + } else if existing_element.is_some() { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected sum item element type", + ))); + } else { + // Insert as a new sum item + drive_operations.push( + LowLevelDriveOperation::insert_for_known_path_key_element( + path, + key.to_vec(), + Element::new_sum_item(new_value), + ), + ); + } + } else { + return Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))); + } + Ok(true) + } + PathKeyElement((path, key, element)) => { + if let Element::SumItem(new_value, _) = element { + // Check if the sum item already exists + let existing_element = self.grove_get_raw_optional( + path.as_slice().into(), + key.as_slice(), + apply_type.to_direct_query_type(), + transaction, + drive_operations, + drive_version, + )?; + + if let Some(Element::SumItem(..)) = existing_element { + return if error_if_exists { + Err(Error::Drive(DriveError::CorruptedDriveState( + "expected no sum item".to_string(), + ))) + } else { + Ok(false) + }; + // Else do nothing + } else if existing_element.is_some() { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected sum item element type", + ))); + } else { + // Insert as a new sum item + drive_operations.push( + LowLevelDriveOperation::insert_for_known_path_key_element( + path, + key, + Element::new_sum_item(new_value), + ), + ); + } + } else { + return Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))); + } + Ok(true) + } + PathFixedSizeKeyRefElement((path, key, element)) => { + if let Element::SumItem(new_value, _) = element { + // Check if the sum item already exists + let existing_element = self.grove_get_raw_optional( + path.as_slice().into(), + key, + apply_type.to_direct_query_type(), + transaction, + drive_operations, + drive_version, + )?; + + if let Some(Element::SumItem(..)) = existing_element { + return if error_if_exists { + Err(Error::Drive(DriveError::CorruptedDriveState( + "expected no sum item".to_string(), + ))) + } else { + Ok(false) + }; + // Else do nothing + } else if existing_element.is_some() { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected sum item element type", + ))); + } else { + // Insert as a new sum item + let path_items: Vec> = path.into_iter().map(Vec::from).collect(); + drive_operations.push( + LowLevelDriveOperation::insert_for_known_path_key_element( + path_items, + key.to_vec(), + Element::new_sum_item(new_value), + ), + ); + } + } else { + return Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))); + } + Ok(true) + } + PathKeyElementSize((key_info_path, key_info, element)) => { + if let Element::SumItem(new_value, _) = element { + match apply_type { + BatchInsertApplyType::StatelessBatchInsert { + in_tree_type, .. + } => { + // Estimate if the sum item with the given size already exists + drive_operations.push(CalculatedCostOperation( + GroveDb::average_case_for_has_raw( + &key_info_path, + &key_info, + element.serialized_size(&drive_version.grove_version)? as u32, + in_tree_type, + &drive_version.grove_version, + )?, + )); + + drive_operations.push( + LowLevelDriveOperation::insert_for_estimated_path_key_element( + key_info_path, + key_info, + Element::new_sum_item(new_value), + ), + ); + Ok(true) + } + BatchInsertApplyType::StatefulBatchInsert => { + Err(Error::Drive(DriveError::NotSupportedPrivate( + "document sizes for stateful insert in batch operations not supported", + ))) + } + } + } else { + Err(Error::Drive(DriveError::CorruptedCodeExecution( + "expected sum item element type", + ))) + } + } + PathKeyUnknownElementSize(_) => Err(Error::Drive(DriveError::NotSupportedPrivate( + "document sizes in batch operations not supported", + ))), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_or_add_to_if_already_exists/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_or_add_to_if_already_exists/v0/mod.rs index 8294a6786b..c9abd72a50 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_or_add_to_if_already_exists/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_sum_item_or_add_to_if_already_exists/v0/mod.rs @@ -178,7 +178,7 @@ impl Drive { if let Element::SumItem(new_value, _) = element { match apply_type { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums, .. + in_tree_type, .. } => { // Estimate if the sum item with the given size already exists drive_operations.push(CalculatedCostOperation( @@ -186,7 +186,7 @@ impl Drive { &key_info_path, &key_info, element.serialized_size(&drive_version.grove_version)? as u32, - in_tree_using_sums, + in_tree_type, &drive_version.grove_version, )?, )); diff --git a/packages/rs-drive/src/util/grove_operations/batch_move_items_in_path_query/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_move_items_in_path_query/v0/mod.rs index f8b2b904cc..15ee4c5bda 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_move_items_in_path_query/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_move_items_in_path_query/v0/mod.rs @@ -89,14 +89,14 @@ impl Drive { }; let delete_operation = match apply_type { BatchMoveApplyType::StatelessBatchMove { - is_sum_tree, + in_tree_type, estimated_key_size, estimated_value_size, .. } => GroveDb::average_case_delete_operation_for_delete::( &KeyInfoPath::from_known_owned_path(path.to_vec()), &KeyInfo::KnownKey(key.to_vec()), - is_sum_tree, + in_tree_type, false, true, 0, @@ -142,14 +142,14 @@ mod tests { util::test_helpers::setup::setup_drive, }; use assert_matches::assert_matches; - use grovedb::{Element, PathQuery, Query, SizedQuery}; + use grovedb::{Element, MaybeTree, PathQuery, Query, SizedQuery}; use grovedb_path::SubtreePath; use platform_version::version::PlatformVersion; #[test] fn test_batch_move_items_in_path_query_success() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -218,7 +218,7 @@ mod tests { // Set up the apply type and drive operations vector let apply_type = BatchMoveApplyType::StatefulBatchMove { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }; let mut drive_operations = Vec::new(); @@ -305,7 +305,7 @@ mod tests { #[test] fn test_batch_move_items_in_path_query_no_elements() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -330,7 +330,7 @@ mod tests { // Set up the apply type and drive operations vector let apply_type = BatchMoveApplyType::StatefulBatchMove { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }; let mut drive_operations = Vec::new(); @@ -351,7 +351,7 @@ mod tests { #[test] fn test_batch_move_items_in_path_query_range_query() { // Set up a test drive instance and transaction - let drive = setup_drive(None); + let drive = setup_drive(None, None); let platform_version = PlatformVersion::latest(); let transaction = drive.grove.start_transaction(); @@ -433,7 +433,7 @@ mod tests { // Set up the apply type and drive operations vector let apply_type = BatchMoveApplyType::StatefulBatchMove { - is_known_to_be_subtree_with_sum: Some((false, false)), + is_known_to_be_subtree_with_sum: Some(MaybeTree::NotTree), }; let mut drive_operations = Vec::new(); diff --git a/packages/rs-drive/src/util/grove_operations/batch_remove_raw/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_remove_raw/v0/mod.rs index d6ef95dad2..89902830ef 100644 --- a/packages/rs-drive/src/util/grove_operations/batch_remove_raw/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/batch_remove_raw/v0/mod.rs @@ -45,9 +45,7 @@ impl Drive { "we should not be seeing internal grovedb operations", ))); } - Some(GroveOp::Delete { .. }) - | Some(GroveOp::DeleteTree { .. }) - | Some(GroveOp::DeleteSumTree { .. }) => false, + Some(GroveOp::Delete { .. }) | Some(GroveOp::DeleteTree { .. }) => false, _ => true, }; @@ -70,7 +68,7 @@ impl Drive { if needs_removal_from_state { let delete_operation = match apply_type { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_key_size, estimated_value_size, } => GroveDb::average_case_delete_operation_for_delete::( diff --git a/packages/rs-drive/src/util/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs index c0afbdaa79..3c212ba544 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_apply_batch_with_add_costs/v0/mod.rs @@ -13,7 +13,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Applies the given groveDB operations batch and gets and passes the costs to `push_drive_operation_result`. - pub(crate) fn grove_apply_batch_with_add_costs_v0( + pub(super) fn grove_apply_batch_with_add_costs_v0( &self, ops: GroveDbOpBatch, validate: bool, diff --git a/packages/rs-drive/src/util/grove_operations/grove_apply_operation/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_apply_operation/v0/mod.rs index dbbb761349..9bb4ab95c4 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_apply_operation/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_apply_operation/v0/mod.rs @@ -7,7 +7,7 @@ use grovedb::TransactionArg; impl Drive { /// Applies the given groveDB operation - pub(crate) fn grove_apply_operation_v0( + pub(super) fn grove_apply_operation_v0( &self, operation: QualifiedGroveDbOp, validate: bool, diff --git a/packages/rs-drive/src/util/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs index a734e406db..9d7a6bc8eb 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_apply_partial_batch_with_add_costs/v0/mod.rs @@ -16,7 +16,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Applies the given groveDB operations batch and gets and passes the costs to `push_drive_operation_result`. - pub(crate) fn grove_apply_partial_batch_with_add_costs_v0( + pub(super) fn grove_apply_partial_batch_with_add_costs_v0( &self, ops: GroveDbOpBatch, validate: bool, diff --git a/packages/rs-drive/src/util/grove_operations/grove_batch_operations_costs/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_batch_operations_costs/v0/mod.rs index 146db3487e..fb1f867e8d 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_batch_operations_costs/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_batch_operations_costs/v0/mod.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; impl Drive { /// Gets the costs for the given groveDB op batch and passes them to `push_drive_operation_result`. - pub(crate) fn grove_batch_operations_costs_v0( + pub(super) fn grove_batch_operations_costs_v0( &self, ops: GroveDbOpBatch, estimated_layer_info: HashMap, diff --git a/packages/rs-drive/src/util/grove_operations/grove_clear/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_clear/v0/mod.rs index ad3152f895..e1de93ec3a 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_clear/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_clear/v0/mod.rs @@ -7,7 +7,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of deleting an element in groveDB to `drive_operations`. - pub(crate) fn grove_clear_v0>( + pub(super) fn grove_clear_v0>( &self, path: SubtreePath<'_, B>, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_delete/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_delete/v0/mod.rs index 13c8a0776e..d5e0c2ab1e 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_delete/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_delete/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of deleting an element in groveDB to `drive_operations`. - pub(crate) fn grove_delete_v0>( + pub(super) fn grove_delete_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_get/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get/v0/mod.rs index c5d473ea6d..3baac60f01 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get/v0/mod.rs @@ -13,7 +13,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the element at the given path from groveDB. /// Pushes the `OperationCost` of getting the element to `drive_operations`. - pub(crate) fn grove_get_v0>( + pub(super) fn grove_get_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], @@ -24,19 +24,19 @@ impl Drive { ) -> Result, Error> { match query_type { QueryType::StatelessQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, estimated_reference_sizes, } => { let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); let key_info = KeyInfo::KnownKey(key.to_vec()); let cost = match query_target { - QueryTarget::QueryTargetTree(flags_size, is_sum_tree) => { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { GroveDb::average_case_for_get_tree( &key_info_path, &key_info, flags_size, - is_sum_tree, + tree_type, in_tree_using_sums, &drive_version.grove_version, ) diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/mod.rs new file mode 100644 index 0000000000..571cd7461b --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/mod.rs @@ -0,0 +1,58 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use dpp::version::drive_versions::DriveVersion; +use grovedb::TransactionArg; +use grovedb_path::SubtreePath; + +impl Drive { + /// Retrieves the total value from a sum tree within groveDB at the specified path and key. + /// The cost of the operation is then appended to `drive_operations` for later processing. + /// + /// # Parameters + /// * `path`: The groveDB hierarchical authenticated structure path where the sum tree is located. + /// * `key`: The key where the sum tree resides within the subtree. + /// * `query_type`: The type of query to perform, either `StatelessDirectQuery` or `StatefulDirectQuery`. + /// * `transaction`: The groveDB transaction associated with this operation. + /// * `drive_operations`: A vector to collect the costs of operations for later computation. + /// * `platform_version`: The platform version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(i64)` if the operation was successful, returning the total value of the sum tree. + /// * `Err(DriveError::UnknownVersionMismatch)` if the platform version does not match known versions. + /// * `Err(DriveError::CorruptedBalancePath)` if the balance path does not refer to a sum tree. + /// * `Err(DriveError::CorruptedCodeExecution)` if trying to query a non-tree element. + pub fn grove_get_big_sum_tree_total_value>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result { + match drive_version + .grove_methods + .basic + .grove_get_big_sum_tree_total_value + { + 0 => self.grove_get_big_sum_tree_total_value_v0( + path, + key, + query_type, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "grove_get_big_sum_tree_total_value".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/v0/mod.rs new file mode 100644 index 0000000000..71ab45ea20 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_big_sum_tree_total_value/v0/mod.rs @@ -0,0 +1,67 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use crate::util::grove_operations::{DirectQueryType, QueryTarget}; +use grovedb::batch::key_info::KeyInfo; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, GroveDb, TransactionArg}; +use grovedb_costs::CostContext; +use grovedb_path::SubtreePath; +use platform_version::version::drive_versions::DriveVersion; + +impl Drive { + /// Gets the element at the given path from groveDB. + /// Pushes the `OperationCost` of getting the element to `drive_operations`. + pub(super) fn grove_get_big_sum_tree_total_value_v0>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result { + match query_type { + DirectQueryType::StatelessDirectQuery { + in_tree_type, + query_target, + } => { + let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); + let key_info = KeyInfo::KnownKey(key.to_vec()); + let cost = match query_target { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { + Ok(GroveDb::average_case_for_get_tree( + &key_info_path, + &key_info, + flags_size, + tree_type, + in_tree_type, + &drive_version.grove_version, + )?) + } + _ => Err(Error::Drive(DriveError::CorruptedCodeExecution( + "can not query a non tree", + ))), + }?; + + drive_operations.push(CalculatedCostOperation(cost)); + Ok(0) + } + DirectQueryType::StatefulDirectQuery => { + let CostContext { value, cost } = + self.grove + .get_raw(path, key, transaction, &drive_version.grove_version); + drive_operations.push(CalculatedCostOperation(cost)); + let element = value.map_err(Error::GroveDB)?; + match element { + Element::BigSumTree(_, value, _) => Ok(value), + _ => Err(Error::Drive(DriveError::CorruptedBalancePath( + "balance path does not refer to a big sum tree", + ))), + } + } + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/mod.rs new file mode 100644 index 0000000000..2be6d7a68e --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/mod.rs @@ -0,0 +1,58 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use dpp::version::drive_versions::DriveVersion; +use grovedb::TransactionArg; +use grovedb_path::SubtreePath; + +impl Drive { + /// Retrieves the total value from a sum tree within groveDB at the specified path and key. + /// The cost of the operation is then appended to `drive_operations` for later processing. + /// + /// # Parameters + /// * `path`: The groveDB hierarchical authenticated structure path where the sum tree is located. + /// * `key`: The key where the sum tree resides within the subtree. + /// * `query_type`: The type of query to perform, either `StatelessDirectQuery` or `StatefulDirectQuery`. + /// * `transaction`: The groveDB transaction associated with this operation. + /// * `drive_operations`: A vector to collect the costs of operations for later computation. + /// * `platform_version`: The platform version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(Option)` if the operation was successful, returning the total value of the sum tree if it exists. + /// * `Err(DriveError::UnknownVersionMismatch)` if the platform version does not match known versions. + /// * `Err(DriveError::CorruptedBalancePath)` if the balance path does not refer to a sum tree. + /// * `Err(DriveError::CorruptedCodeExecution)` if trying to query a non-tree element. + pub fn grove_get_optional_sum_tree_total_value>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result, Error> { + match drive_version + .grove_methods + .basic + .grove_get_optional_sum_tree_total_value + { + 0 => self.grove_get_optional_sum_tree_total_value_v0( + path, + key, + query_type, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "grove_get_optional_sum_tree_total_value".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/v0/mod.rs new file mode 100644 index 0000000000..59fb056344 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_optional_sum_tree_total_value/v0/mod.rs @@ -0,0 +1,72 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use crate::util::grove_operations::{DirectQueryType, QueryTarget}; +use grovedb::batch::key_info::KeyInfo; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, GroveDb, TransactionArg}; +use grovedb_costs::CostContext; +use grovedb_path::SubtreePath; +use platform_version::version::drive_versions::DriveVersion; + +impl Drive { + /// Gets the element at the given path from groveDB. + /// Pushes the `OperationCost` of getting the element to `drive_operations`. + pub(super) fn grove_get_optional_sum_tree_total_value_v0>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result, Error> { + match query_type { + DirectQueryType::StatelessDirectQuery { + in_tree_type: in_tree_using_sums, + query_target, + } => { + let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); + let key_info = KeyInfo::KnownKey(key.to_vec()); + let cost = match query_target { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { + Ok(GroveDb::average_case_for_get_tree( + &key_info_path, + &key_info, + flags_size, + tree_type, + in_tree_using_sums, + &drive_version.grove_version, + )?) + } + _ => Err(Error::Drive(DriveError::CorruptedCodeExecution( + "can not query a non tree", + ))), + }?; + + drive_operations.push(CalculatedCostOperation(cost)); + Ok(Some(0)) + } + DirectQueryType::StatefulDirectQuery => { + let CostContext { value, cost } = self.grove.get_raw_optional( + path, + key, + transaction, + &drive_version.grove_version, + ); + drive_operations.push(CalculatedCostOperation(cost)); + let Some(element) = value.map_err(Error::GroveDB)? else { + return Ok(None); + }; + match element { + Element::SumTree(_, value, _) => Ok(Some(value)), + _ => Err(Error::Drive(DriveError::CorruptedBalancePath( + "balance path does not refer to a sum tree", + ))), + } + } + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_path_query/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_path_query/v0/mod.rs index 9997184f5f..80a48f0509 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_path_query/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_path_query/v0/mod.rs @@ -10,7 +10,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB path query. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_get_path_query_v0( + pub(super) fn grove_get_path_query_v0( &self, path_query: &PathQuery, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_or_sum_results/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_or_sum_results/v0/mod.rs index 18753f813b..56625e4b2f 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_or_sum_results/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_or_sum_results/v0/mod.rs @@ -10,7 +10,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB path query. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_get_path_query_serialized_or_sum_results_v0( + pub(super) fn grove_get_path_query_serialized_or_sum_results_v0( &self, path_query: &PathQuery, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_results/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_results/v0/mod.rs index 584f36d4d6..cb58485487 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_results/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_serialized_results/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB path query. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_get_path_query_serialized_results_v0( + pub(super) fn grove_get_path_query_serialized_results_v0( &self, path_query: &PathQuery, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs index bd914b73b8..4ee57d66e8 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_path_query_with_optional/v0/mod.rs @@ -10,7 +10,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB path query. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_get_path_query_with_optional_v0( + pub(super) fn grove_get_path_query_with_optional_v0( &self, path_query: &PathQuery, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query/v0/mod.rs index 3b9a9614a5..ecc4d49907 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query/v0/mod.rs @@ -11,7 +11,7 @@ impl Drive { /// Pushes the cost to `drive_operations` and returns the return value. /// Verbose should be generally set to false unless one needs to prove /// subsets of a proof. - pub(crate) fn grove_get_proved_path_query_v0( + pub(super) fn grove_get_proved_path_query_v0( &self, path_query: &PathQuery, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_with_conditional/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_with_conditional/v0/mod.rs index 3d3d4aad5d..40a47aa901 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_with_conditional/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_with_conditional/v0/mod.rs @@ -12,7 +12,7 @@ impl Drive { /// Pushes the cost to `drive_operations` and returns the return value. /// Verbose should be generally set to false unless one needs to prove /// subsets of a proof. - pub(crate) fn grove_get_proved_path_query_with_conditional_v0>( + pub(super) fn grove_get_proved_path_query_with_conditional_v0>( &self, root_path: SubtreePath, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw/v0/mod.rs index a564abc273..0d6778540c 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_raw/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw/v0/mod.rs @@ -13,7 +13,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// grove_get_raw basically means that there are no reference hops, this only matters /// when calculating worst case costs - pub(crate) fn grove_get_raw_v0>( + pub(super) fn grove_get_raw_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], @@ -24,18 +24,18 @@ impl Drive { ) -> Result, Error> { match direct_query_type { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, } => { let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); let key_info = KeyInfo::KnownKey(key.to_vec()); let cost = match query_target { - QueryTarget::QueryTargetTree(flags_size, is_sum_tree) => { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { GroveDb::average_case_for_get_tree( &key_info_path, &key_info, flags_size, - is_sum_tree, + tree_type, in_tree_using_sums, &drive_version.grove_version, ) diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_item/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_item/mod.rs new file mode 100644 index 0000000000..cd9d7a4d92 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_item/mod.rs @@ -0,0 +1,55 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; + +use dpp::version::drive_versions::DriveVersion; + +use grovedb::TransactionArg; +use grovedb_path::SubtreePath; + +impl Drive { + /// Handles the retrieval of a raw element from GroveDB at the specified path and key. + /// The operation cost is added to `drive_operations` for later processing. + /// + /// # Parameters + /// * `path`: The groveDB hierarchical authenticated structure path from where the element is to be retrieved. + /// * `key`: The key of the element to be retrieved from the subtree. + /// * `direct_query_type`: The type of query to perform, whether stateless or stateful. + /// * `transaction`: The groveDB transaction associated with this operation. + /// * `drive_operations`: A vector to collect the costs of operations for later computation. + /// * `platform_version`: The platform version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(Some(Element))` if the operation was successful and the element was found. + /// * `Ok(None)` if the operation was successful but the element was not found. + /// * `Err(DriveError::UnknownVersionMismatch)` if the platform version does not match known versions. + pub fn grove_get_raw_item>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + direct_query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result, Error> { + match drive_version.grove_methods.basic.grove_get_raw_item { + 0 => self.grove_get_raw_item_v0( + path, + key, + direct_query_type, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "grove_get_raw_item".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_item/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_item/v0/mod.rs new file mode 100644 index 0000000000..4f7dc34a36 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_item/v0/mod.rs @@ -0,0 +1,83 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use crate::util::grove_operations::{DirectQueryType, QueryTarget}; +use grovedb::batch::key_info::KeyInfo; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, GroveDb, TransactionArg}; +use grovedb_costs::CostContext; +use grovedb_path::SubtreePath; +use itertools::Itertools; +use platform_version::version::drive_versions::DriveVersion; + +impl Drive { + /// grove_get_raw_item basically means that there are no reference hops, this only matters + /// when calculating worst case costs + pub(super) fn grove_get_raw_item_v0>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + direct_query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result, Error> { + match direct_query_type { + DirectQueryType::StatelessDirectQuery { + in_tree_type: in_tree_using_sums, + query_target, + } => { + let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); + let key_info = KeyInfo::KnownKey(key.to_vec()); + let cost = match query_target { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { + GroveDb::average_case_for_get_tree( + &key_info_path, + &key_info, + flags_size, + tree_type, + in_tree_using_sums, + &drive_version.grove_version, + ) + } + QueryTarget::QueryTargetValue(estimated_value_size) => { + GroveDb::average_case_for_get_raw( + &key_info_path, + &key_info, + estimated_value_size, + in_tree_using_sums, + &drive_version.grove_version, + ) + } + }?; + + drive_operations.push(CalculatedCostOperation(cost)); + Ok(vec![]) + } + DirectQueryType::StatefulDirectQuery => { + //todo remove path clone + let CostContext { value, cost } = self.grove.get_raw( + path.clone(), + key, + transaction, + &drive_version.grove_version, + ); + drive_operations.push(CalculatedCostOperation(cost)); + let element = value.map_err(Error::GroveDB)?; + match element { + Element::Item(value, _) => Ok(value), + _ => Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "path {}/0x{} does not refer to an item", + path.to_vec() + .iter() + .map(|bytes| format!("0x{}", hex::encode(bytes))) + .join("/"), + hex::encode(key) + )))), + } + } + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional/v0/mod.rs index 9c8f567fa9..90e2b2b004 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional/v0/mod.rs @@ -24,18 +24,18 @@ impl Drive { ) -> Result, Error> { match direct_query_type { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, } => { let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); let key_info = KeyInfo::KnownKey(key.to_vec()); let cost = match query_target { - QueryTarget::QueryTargetTree(flags_size, is_sum_tree) => { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { GroveDb::average_case_for_get_tree( &key_info_path, &key_info, flags_size, - is_sum_tree, + tree_type, in_tree_using_sums, &drive_version.grove_version, ) diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/mod.rs new file mode 100644 index 0000000000..667e956ce9 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/mod.rs @@ -0,0 +1,59 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; + +use dpp::version::drive_versions::DriveVersion; + +use grovedb::TransactionArg; +use grovedb_path::SubtreePath; + +impl Drive { + /// Handles the retrieval of a raw element from GroveDB at the specified path and key. + /// The operation cost is added to `drive_operations` for later processing. + /// + /// # Parameters + /// * `path`: The groveDB hierarchical authenticated structure path from where the element is to be retrieved. + /// * `key`: The key of the element to be retrieved from the subtree. + /// * `direct_query_type`: The type of query to perform, whether stateless or stateful. + /// * `transaction`: The groveDB transaction associated with this operation. + /// * `drive_operations`: A vector to collect the costs of operations for later computation. + /// * `platform_version`: The platform version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(Some(Element))` if the operation was successful and the element was found. + /// * `Ok(None)` if the operation was successful but the element was not found. + /// * `Err(DriveError::UnknownVersionMismatch)` if the platform version does not match known versions. + pub fn grove_get_raw_optional_item>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + direct_query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result>, Error> { + match drive_version + .grove_methods + .basic + .grove_get_raw_optional_item + { + 0 => self.grove_get_raw_optional_item_v0( + path, + key, + direct_query_type, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "grove_get_raw_optional_item".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/v0/mod.rs new file mode 100644 index 0000000000..3ca57601fd --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_optional_item/v0/mod.rs @@ -0,0 +1,84 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use crate::util::grove_operations::{DirectQueryType, QueryTarget}; +use grovedb::batch::key_info::KeyInfo; +use grovedb::batch::KeyInfoPath; +use grovedb::{Element, GroveDb, TransactionArg}; +use grovedb_costs::CostContext; +use grovedb_path::SubtreePath; +use itertools::Itertools; +use platform_version::version::drive_versions::DriveVersion; + +impl Drive { + /// grove_get_raw_item basically means that there are no reference hops, this only matters + /// when calculating worst case costs + pub(super) fn grove_get_raw_optional_item_v0>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + direct_query_type: DirectQueryType, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result>, Error> { + match direct_query_type { + DirectQueryType::StatelessDirectQuery { + in_tree_type: in_tree_using_sums, + query_target, + } => { + let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); + let key_info = KeyInfo::KnownKey(key.to_vec()); + let cost = match query_target { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { + GroveDb::average_case_for_get_tree( + &key_info_path, + &key_info, + flags_size, + tree_type, + in_tree_using_sums, + &drive_version.grove_version, + ) + } + QueryTarget::QueryTargetValue(estimated_value_size) => { + GroveDb::average_case_for_get_raw( + &key_info_path, + &key_info, + estimated_value_size, + in_tree_using_sums, + &drive_version.grove_version, + ) + } + }?; + + drive_operations.push(CalculatedCostOperation(cost)); + Ok(None) + } + DirectQueryType::StatefulDirectQuery => { + //todo remove path clone + let CostContext { value, cost } = self.grove.get_raw_optional( + path.clone(), + key, + transaction, + &drive_version.grove_version, + ); + drive_operations.push(CalculatedCostOperation(cost)); + let element = value.map_err(Error::GroveDB)?; + match element { + Some(Element::Item(value, _)) => Ok(Some(value)), + None => Ok(None), + _ => Err(Error::Drive(DriveError::CorruptedDriveState(format!( + "path {}/0x{} does not refer to an item", + path.to_vec() + .iter() + .map(|bytes| format!("0x{}", hex::encode(bytes))) + .join("/"), + hex::encode(key) + )))), + } + } + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query/v0/mod.rs index eebeb4b524..2deec8ba8b 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query/v0/mod.rs @@ -10,7 +10,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB raw path query. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_get_raw_path_query_v0( + pub(super) fn grove_get_raw_path_query_v0( &self, path_query: &PathQuery, transaction: TransactionArg, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query_with_optional/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query_with_optional/v0/mod.rs index add7c65d91..1e852fcb77 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query_with_optional/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_path_query_with_optional/v0/mod.rs @@ -10,7 +10,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB path query. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_get_raw_path_query_with_optional_v0( + pub(super) fn grove_get_raw_path_query_with_optional_v0( &self, path_query: &PathQuery, error_if_intermediate_path_tree_not_present: bool, diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_raw_value_u64_from_encoded_var_vec/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_raw_value_u64_from_encoded_var_vec/v0/mod.rs index 368a7d2933..07418407bb 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_raw_value_u64_from_encoded_var_vec/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_raw_value_u64_from_encoded_var_vec/v0/mod.rs @@ -10,7 +10,7 @@ use integer_encoding::VarInt; impl Drive { /// grove_get_direct_u64 is a helper function to get a - pub(crate) fn grove_get_raw_value_u64_from_encoded_var_vec_v0>( + pub(super) fn grove_get_raw_value_u64_from_encoded_var_vec_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_sum_tree_total_value/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_sum_tree_total_value/v0/mod.rs index 65bd03f3e3..f163c9ac51 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_sum_tree_total_value/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_sum_tree_total_value/v0/mod.rs @@ -25,18 +25,18 @@ impl Drive { ) -> Result { match query_type { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, } => { let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); let key_info = KeyInfo::KnownKey(key.to_vec()); let cost = match query_target { - QueryTarget::QueryTargetTree(flags_size, is_sum_tree) => { + QueryTarget::QueryTargetTree(flags_size, tree_type) => { Ok(GroveDb::average_case_for_get_tree( &key_info_path, &key_info, flags_size, - is_sum_tree, + tree_type, in_tree_using_sums, &drive_version.grove_version, )?) diff --git a/packages/rs-drive/src/util/grove_operations/grove_has_raw/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_has_raw/v0/mod.rs index 52b3eaaa96..f6b57a7c6f 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_has_raw/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_has_raw/v0/mod.rs @@ -14,7 +14,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Gets the return value and the cost of a groveDB `has_raw` operation. /// Pushes the cost to `drive_operations` and returns the return value. - pub(crate) fn grove_has_raw_v0>( + pub(super) fn grove_has_raw_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], @@ -25,18 +25,18 @@ impl Drive { ) -> Result { let CostContext { value, cost } = match query_type { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, } => { let key_info_path = KeyInfoPath::from_known_owned_path(path.to_vec()); let key_info = KeyInfo::KnownKey(key.to_vec()); let cost = match query_target { - QueryTarget::QueryTargetTree(flags_len, is_sum_tree) => { + QueryTarget::QueryTargetTree(flags_len, tree_type) => { GroveDb::average_case_for_has_raw_tree( &key_info_path, &key_info, flags_len, - is_sum_tree, + tree_type, in_tree_using_sums, &drive_version.grove_version, )? diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert/v0/mod.rs index f9c81c65c7..f949ecc605 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of inserting an element in groveDB to `drive_operations`. - pub(crate) fn grove_insert_v0>( + pub(super) fn grove_insert_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_sum_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_sum_tree/v0/mod.rs index a025023bf3..2ea0ae20d8 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_sum_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_sum_tree/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of inserting an empty sum tree in groveDB to `drive_operations`. - pub fn grove_insert_empty_sum_tree_v0>( + pub(super) fn grove_insert_empty_sum_tree_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs index 6628036899..4a0a2d3488 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of inserting an empty tree in groveDB to `drive_operations`. - pub(crate) fn grove_insert_empty_tree_v0>( + pub(super) fn grove_insert_empty_tree_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists/v0/mod.rs index b03297457c..4d27e25459 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of inserting an element in groveDB where the path key does not yet exist /// to `drive_operations`. - pub(crate) fn grove_insert_if_not_exists_v0>( + pub(super) fn grove_insert_if_not_exists_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists_return_existing_element/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists_return_existing_element/v0/mod.rs index 69b55ba2d7..86bb679a39 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists_return_existing_element/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_if_not_exists_return_existing_element/v0/mod.rs @@ -9,7 +9,7 @@ use platform_version::version::drive_versions::DriveVersion; impl Drive { /// Pushes the `OperationCost` of inserting an element in groveDB where the path key does not yet exist /// to `drive_operations`. - pub(crate) fn grove_insert_if_not_exists_return_existing_element_v0>( + pub(super) fn grove_insert_if_not_exists_return_existing_element_v0>( &self, path: SubtreePath<'_, B>, key: &[u8], diff --git a/packages/rs-drive/src/util/grove_operations/mod.rs b/packages/rs-drive/src/util/grove_operations/mod.rs index 8178d007b2..098d8259cd 100644 --- a/packages/rs-drive/src/util/grove_operations/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/mod.rs @@ -21,6 +21,9 @@ pub mod grove_delete; /// Fetch raw grove data pub mod grove_get_raw; +/// Fetch raw grove data and match that is item +pub mod grove_get_raw_item; + /// Fetch raw grove data if it exists pub mod grove_get_raw_optional; @@ -57,6 +60,9 @@ pub mod grove_has_raw; /// Batch insert operation into empty tree pub mod batch_insert_empty_tree; +/// Batch insert operation into empty sum tree +pub mod batch_insert_empty_sum_tree; + /// Batch insert operation into empty tree, but only if it doesn't already exist pub mod batch_insert_empty_tree_if_not_exists; @@ -126,12 +132,21 @@ pub mod grove_get_proved_path_query_with_conditional; /// Inserts an element if it does not exist and returns the existing element if it does in GroveDB. pub mod grove_insert_if_not_exists_return_existing_element; +/// Batch inserts sum item if not already existing +pub mod batch_insert_sum_item_if_not_exists; /// Moved items that are found in a path query to a new path. pub mod batch_move_items_in_path_query; +/// Get the total value from a big sum tree +pub mod grove_get_big_sum_tree_total_value; +/// Get total value from sum tree in grove if it exists +pub mod grove_get_optional_sum_tree_total_value; +/// Fetch raw grove data if it exists, None otherwise +pub mod grove_get_raw_optional_item; + use grovedb_costs::CostContext; -use grovedb::EstimatedLayerInformation; +use grovedb::{EstimatedLayerInformation, MaybeTree, TreeType}; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; @@ -179,7 +194,7 @@ pub enum BatchDeleteApplyType { /// Stateless batch delete StatelessBatchDelete { /// Are we deleting in a sum tree - is_sum_tree: bool, + in_tree_type: TreeType, /// What is the estimated key size estimated_key_size: u32, /// What is the estimated value size @@ -188,7 +203,7 @@ pub enum BatchDeleteApplyType { /// Stateful batch delete StatefulBatchDelete { /// Are we known to be in a subtree and does this subtree have sums - is_known_to_be_subtree_with_sum: Option<(IsSubTree, IsSumSubTree)>, + is_known_to_be_subtree_with_sum: Option, }, } @@ -198,9 +213,9 @@ pub enum BatchMoveApplyType { /// Stateless batch move StatelessBatchMove { /// Are we moving from inside a sum tree - in_tree_using_sums: bool, + in_tree_type: TreeType, /// Are we moving a sum tree - is_sum_tree: bool, + tree_type: TreeType, /// What is the estimated key size estimated_key_size: u32, /// What is the estimated value size @@ -211,7 +226,7 @@ pub enum BatchMoveApplyType { /// Stateful batch move StatefulBatchMove { /// Are we known to be in a subtree and does this subtree have sums - is_known_to_be_subtree_with_sum: Option<(IsSubTree, IsSumSubTree)>, + is_known_to_be_subtree_with_sum: Option, }, } @@ -226,7 +241,7 @@ pub enum BatchDeleteUpTreeApplyType { /// Stateful batch delete StatefulBatchDelete { /// Are we known to be in a subtree and does this subtree have sums - is_known_to_be_subtree_with_sum: Option<(IsSubTree, IsSumSubTree)>, + is_known_to_be_subtree_with_sum: Option, }, } @@ -237,9 +252,9 @@ pub enum BatchInsertTreeApplyType { /// Stateless batch insert tree StatelessBatchInsertTree { /// Does this tree use sums? - in_tree_using_sums: bool, + in_tree_type: TreeType, /// Are we inserting in a sum tree - is_sum_tree: bool, + tree_type: TreeType, /// The flags length flags_len: FlagsLen, }, @@ -259,12 +274,12 @@ impl BatchInsertTreeApplyType { pub(crate) fn to_direct_query_type(self) -> DirectQueryType { match self { BatchInsertTreeApplyType::StatelessBatchInsertTree { - in_tree_using_sums, - is_sum_tree, + in_tree_type, + tree_type, flags_len, } => DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, - query_target: QueryTarget::QueryTargetTree(flags_len, is_sum_tree), + in_tree_type, + query_target: QueryTarget::QueryTargetTree(flags_len, tree_type), }, BatchInsertTreeApplyType::StatefulBatchInsertTree => { DirectQueryType::StatefulDirectQuery @@ -274,11 +289,12 @@ impl BatchInsertTreeApplyType { } /// Batch insert apply type +#[derive(Clone, Copy)] pub enum BatchInsertApplyType { /// Stateless batch insert StatelessBatchInsert { /// Does this tree use sums? - in_tree_using_sums: bool, + in_tree_type: TreeType, /// the type of Target (Tree or Value) target: QueryTarget, }, @@ -297,10 +313,10 @@ impl BatchInsertApplyType { pub(crate) fn to_direct_query_type(&self) -> DirectQueryType { match self { BatchInsertApplyType::StatelessBatchInsert { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, target, } => DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: *in_tree_using_sums, + in_tree_type: *in_tree_using_sums, query_target: *target, }, BatchInsertApplyType::StatefulBatchInsert => DirectQueryType::StatefulDirectQuery, @@ -316,7 +332,7 @@ pub type FlagsLen = u32; /// Query target pub enum QueryTarget { /// tree - QueryTargetTree(FlagsLen, IsSumTree), + QueryTargetTree(FlagsLen, TreeType), /// value QueryTargetValue(u32), } @@ -325,9 +341,8 @@ impl QueryTarget { /// Length pub(crate) fn len(&self) -> u32 { match self { - QueryTarget::QueryTargetTree(flags_len, is_sum_tree) => { - let len = if *is_sum_tree { 11 } else { 3 }; - *flags_len + len + QueryTarget::QueryTargetTree(flags_len, tree_type) => { + *flags_len + tree_type.inner_node_type().cost() + 3 } QueryTarget::QueryTargetValue(len) => *len, } @@ -341,7 +356,7 @@ pub enum DirectQueryType { /// Stateless direct query StatelessDirectQuery { /// Does this tree use sums? - in_tree_using_sums: bool, + in_tree_type: TreeType, /// the type of Target (Tree or Value) query_target: QueryTarget, }, @@ -353,10 +368,10 @@ impl From for QueryType { fn from(value: DirectQueryType) -> Self { match value { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, + in_tree_type, query_target, } => QueryType::StatelessQuery { - in_tree_using_sums, + in_tree_type, query_target, estimated_reference_sizes: vec![], }, @@ -397,10 +412,10 @@ impl DirectQueryType { pub(crate) fn add_reference_sizes(self, reference_sizes: Vec) -> QueryType { match self { DirectQueryType::StatelessDirectQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, } => QueryType::StatelessQuery { - in_tree_using_sums, + in_tree_type: in_tree_using_sums, query_target, estimated_reference_sizes: reference_sizes, }, @@ -415,7 +430,7 @@ pub enum QueryType { /// Stateless query StatelessQuery { /// Does this tree use sums? - in_tree_using_sums: bool, + in_tree_type: TreeType, /// the type of Target (Tree or Value) query_target: QueryTarget, /// The estimated sizes of references @@ -429,11 +444,11 @@ impl From for QueryType { fn from(value: BatchDeleteApplyType) -> Self { match value { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_value_size, .. } => QueryType::StatelessQuery { - in_tree_using_sums: is_sum_tree, + in_tree_type: is_sum_tree, query_target: QueryTarget::QueryTargetValue(estimated_value_size), estimated_reference_sizes: vec![], }, @@ -446,11 +461,11 @@ impl From<&BatchDeleteApplyType> for QueryType { fn from(value: &BatchDeleteApplyType) -> Self { match value { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_value_size, .. } => QueryType::StatelessQuery { - in_tree_using_sums: *is_sum_tree, + in_tree_type: *is_sum_tree, query_target: QueryTarget::QueryTargetValue(*estimated_value_size), estimated_reference_sizes: vec![], }, @@ -463,11 +478,11 @@ impl From for DirectQueryType { fn from(value: BatchDeleteApplyType) -> Self { match value { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_value_size, .. } => DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: is_sum_tree, + in_tree_type: is_sum_tree, query_target: QueryTarget::QueryTargetValue(estimated_value_size), }, BatchDeleteApplyType::StatefulBatchDelete { .. } => { @@ -481,11 +496,11 @@ impl From<&BatchDeleteApplyType> for DirectQueryType { fn from(value: &BatchDeleteApplyType) -> Self { match value { BatchDeleteApplyType::StatelessBatchDelete { - is_sum_tree, + in_tree_type: is_sum_tree, estimated_value_size, .. } => DirectQueryType::StatelessDirectQuery { - in_tree_using_sums: *is_sum_tree, + in_tree_type: *is_sum_tree, query_target: QueryTarget::QueryTargetValue(*estimated_value_size), }, BatchDeleteApplyType::StatefulBatchDelete { .. } => { diff --git a/packages/rs-drive/src/util/object_size_info/contract_info.rs b/packages/rs-drive/src/util/object_size_info/contract_info.rs index d5bde596fa..7e8713f62d 100644 --- a/packages/rs-drive/src/util/object_size_info/contract_info.rs +++ b/packages/rs-drive/src/util/object_size_info/contract_info.rs @@ -1,10 +1,14 @@ #[cfg(feature = "server")] use crate::drive::contract::DataContractFetchInfo; +#[cfg(feature = "server")] use crate::drive::Drive; +#[cfg(feature = "server")] use crate::error::document::DocumentError; +#[cfg(feature = "server")] use crate::error::Error; #[cfg(feature = "server")] use crate::fees::op::LowLevelDriveOperation; +#[cfg(feature = "server")] use dpp::block::block_info::BlockInfo; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::DocumentTypeRef; @@ -13,6 +17,7 @@ use dpp::identifier::Identifier; use dpp::ProtocolError; #[cfg(feature = "server")] use grovedb::TransactionArg; +#[cfg(feature = "server")] use platform_version::version::PlatformVersion; use std::sync::Arc; diff --git a/packages/rs-drive/src/util/operations/apply_batch_grovedb_operations/v0/mod.rs b/packages/rs-drive/src/util/operations/apply_batch_grovedb_operations/v0/mod.rs index af240c9490..22622d5adf 100644 --- a/packages/rs-drive/src/util/operations/apply_batch_grovedb_operations/v0/mod.rs +++ b/packages/rs-drive/src/util/operations/apply_batch_grovedb_operations/v0/mod.rs @@ -9,7 +9,7 @@ use std::collections::HashMap; impl Drive { /// Applies a batch of groveDB operations if apply is True, otherwise gets the cost of the operations. - pub(crate) fn apply_batch_grovedb_operations_v0( + pub(super) fn apply_batch_grovedb_operations_v0( &self, estimated_costs_only_with_layer_info: Option< HashMap, diff --git a/packages/rs-drive/src/util/test_helpers/mod.rs b/packages/rs-drive/src/util/test_helpers/mod.rs index 81447b4691..8600f2eddb 100644 --- a/packages/rs-drive/src/util/test_helpers/mod.rs +++ b/packages/rs-drive/src/util/test_helpers/mod.rs @@ -40,18 +40,25 @@ pub fn setup_contract( drive: &Drive, path: &str, contract_id: Option<[u8; 32]>, + owner_id: Option<[u8; 32]>, + contract_modification: Option, transaction: TransactionArg, + use_platform_version: Option<&PlatformVersion>, ) -> DataContract { - let platform_version = PlatformVersion::latest(); - let contract = json_document_to_contract_with_ids( + let platform_version = use_platform_version.unwrap_or(PlatformVersion::latest()); + let mut contract = json_document_to_contract_with_ids( path, contract_id.map(Identifier::from), - None, + owner_id.map(Identifier::from), false, //no need to validate the data contracts in tests for drive platform_version, ) .expect("expected to get json based contract"); + if let Some(contract_modification) = contract_modification { + contract_modification(&mut contract); + } + drive .apply_contract( &contract, diff --git a/packages/rs-drive/src/util/test_helpers/setup.rs b/packages/rs-drive/src/util/test_helpers/setup.rs index d80f600def..bbb935219c 100644 --- a/packages/rs-drive/src/util/test_helpers/setup.rs +++ b/packages/rs-drive/src/util/test_helpers/setup.rs @@ -36,10 +36,14 @@ impl Default for SetupFeePoolsOptions { #[cfg(feature = "full")] /// Sets up Drive using a temporary directory and the optionally given Drive configuration settings. -pub fn setup_drive(drive_config: Option) -> Drive { +pub fn setup_drive( + drive_config: Option, + specific_platform_version: Option<&PlatformVersion>, +) -> Drive { let tmp_dir = TempDir::new().unwrap(); - let (drive, _) = Drive::open(tmp_dir, drive_config).expect("should open Drive successfully"); + let (drive, _) = Drive::open(tmp_dir, drive_config, specific_platform_version) + .expect("should open Drive successfully"); drive } @@ -49,10 +53,13 @@ pub fn setup_drive(drive_config: Option) -> Drive { pub fn setup_drive_with_initial_state_structure( specific_platform_version: Option<&PlatformVersion>, ) -> Drive { - let drive = setup_drive(Some(DriveConfig { - batching_consistency_verification: true, - ..Default::default() - })); + let drive = setup_drive( + Some(DriveConfig { + batching_consistency_verification: true, + ..Default::default() + }), + specific_platform_version, + ); let platform_version = specific_platform_version.unwrap_or(PlatformVersion::latest()); drive diff --git a/packages/rs-drive/src/util/type_constants.rs b/packages/rs-drive/src/util/type_constants.rs index 517a08a275..8979cca62a 100644 --- a/packages/rs-drive/src/util/type_constants.rs +++ b/packages/rs-drive/src/util/type_constants.rs @@ -11,6 +11,8 @@ pub const DEFAULT_HASH_SIZE_U32: u32 = 32; /// Default float size pub const DEFAULT_FLOAT_SIZE: u32 = 8; /// u64 size +pub const U64_SIZE_U32: u32 = 8; +/// u64 size pub const U64_SIZE_U16: u16 = 8; /// u64 size pub const U64_SIZE_U8: u8 = 8; diff --git a/packages/rs-drive/src/verify/mod.rs b/packages/rs-drive/src/verify/mod.rs index b4c627718e..18474b4bbb 100644 --- a/packages/rs-drive/src/verify/mod.rs +++ b/packages/rs-drive/src/verify/mod.rs @@ -12,6 +12,7 @@ pub mod system; /// Verifies that a state transition contents exist in the proof pub mod state_transition; +mod tokens; pub mod voting; /// Represents the root hash of the grovedb tree 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 d424fbe328..8225f4f666 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 @@ -11,23 +11,22 @@ use dpp::identity::PartialIdentity; use dpp::platform_value::btreemap_extensions::BTreeValueMapHelper; use dpp::state_transition::data_contract_create_transition::accessors::DataContractCreateTransitionAccessorsV0; use dpp::state_transition::data_contract_update_transition::accessors::DataContractUpdateTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::batch_transition::document_base_transition::v0::v0_methods::DocumentBaseTransitionV0Methods; +use dpp::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::BatchedTransitionRef; use dpp::state_transition::identity_create_transition::accessors::IdentityCreateTransitionAccessorsV0; use dpp::state_transition::identity_credit_transfer_transition::accessors::IdentityCreditTransferTransitionAccessorsV0; use dpp::state_transition::identity_credit_withdrawal_transition::accessors::IdentityCreditWithdrawalTransitionAccessorsV0; use dpp::state_transition::identity_topup_transition::accessors::IdentityTopUpTransitionAccessorsV0; use dpp::state_transition::identity_update_transition::accessors::IdentityUpdateTransitionAccessorsV0; use dpp::state_transition::{StateTransition, StateTransitionLike}; -use dpp::state_transition::documents_batch_transition::document_create_transition::DocumentFromCreateTransition; -use dpp::state_transition::documents_batch_transition::document_delete_transition::v0::v0_methods::DocumentDeleteTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_replace_transition::DocumentFromReplaceTransition; -use dpp::state_transition::documents_batch_transition::document_replace_transition::v0::v0_methods::DocumentReplaceTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::document_purchase_transition::v0::v0_methods::DocumentPurchaseTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; +use dpp::state_transition::batch_transition::document_base_transition::document_base_transition_trait::DocumentBaseTransitionAccessors; +use dpp::state_transition::batch_transition::document_create_transition::DocumentFromCreateTransition; +use dpp::state_transition::batch_transition::document_replace_transition::DocumentFromReplaceTransition; +use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::v0::v0_methods::DocumentTransferTransitionV0Methods; +use dpp::state_transition::batch_transition::batched_transition::document_transition::{DocumentTransition, DocumentTransitionV0Methods}; +use dpp::state_transition::batch_transition::batched_transition::document_update_price_transition::v0::v0_methods::DocumentUpdatePriceTransitionV0Methods; use dpp::state_transition::masternode_vote_transition::accessors::MasternodeVoteTransitionAccessorsV0; use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::state_transition::proof_result::StateTransitionProofResult::{VerifiedBalanceTransfer, VerifiedDataContract, VerifiedDocuments, VerifiedIdentity, VerifiedMasternodeVote, VerifiedPartialIdentity}; @@ -91,11 +90,11 @@ impl Drive { } Ok((root_hash, VerifiedDataContract(contract))) } - StateTransition::DocumentsBatch(documents_batch_transition) => { - if documents_batch_transition.transitions().len() > 1 { + StateTransition::Batch(documents_batch_transition) => { + if documents_batch_transition.transitions_len() > 1 { return Err(Error::Proof(ProofError::InvalidTransition(format!("version {} does not support more than one document in a document batch transition", platform_version.protocol_version)))); } - let Some(transition) = documents_batch_transition.transitions().first() else { + let Some(transition) = documents_batch_transition.first_transition() else { return Err(Error::Proof(ProofError::InvalidTransition( "no transition in a document batch transition".to_string(), ))); @@ -103,168 +102,193 @@ impl Drive { let owner_id = documents_batch_transition.owner_id(); - let data_contract_id = transition.data_contract_id(); + match transition { + BatchedTransitionRef::Document(document_transition) => { + let data_contract_id = document_transition.data_contract_id(); - let contract = known_contracts_provider_fn(&data_contract_id)?.ok_or( - Error::Proof(ProofError::UnknownContract(format!( - "unknown contract with id {}", - data_contract_id - ))), - )?; + let contract = known_contracts_provider_fn(&data_contract_id)?.ok_or( + Error::Proof(ProofError::UnknownContract(format!( + "unknown contract with id {}", + data_contract_id + ))), + )?; - let document_type = contract - .document_type_for_name(transition.document_type_name()) - .map_err(|e| { - Error::Proof(ProofError::UnknownContract(format!( - "cannot fetch contract for document {} with id {}: {}", - transition.document_type_name(), - transition.data_contract_id(), - e - ))) - })?; + let document_type = contract + .document_type_for_name(document_transition.document_type_name()) + .map_err(|e| { + Error::Proof(ProofError::UnknownContract(format!( + "cannot fetch contract for document {} with id {}: {}", + document_transition.document_type_name(), + document_transition.data_contract_id(), + e + ))) + })?; - let contested_status = - if let DocumentTransition::Create(create_transition) = transition { - if create_transition.prefunded_voting_balance().is_some() { - SingleDocumentDriveQueryContestedStatus::Contested - } else { - SingleDocumentDriveQueryContestedStatus::NotContested - } - } else { - SingleDocumentDriveQueryContestedStatus::NotContested - }; + let contested_status = + if let DocumentTransition::Create(create_transition) = + document_transition + { + if create_transition.prefunded_voting_balance().is_some() { + SingleDocumentDriveQueryContestedStatus::Contested + } else { + SingleDocumentDriveQueryContestedStatus::NotContested + } + } else { + SingleDocumentDriveQueryContestedStatus::NotContested + }; - match transition { - DocumentTransition::Create(_) => {} - DocumentTransition::Replace(_) => {} - DocumentTransition::Delete(_) => {} - DocumentTransition::Transfer(_) => {} - DocumentTransition::UpdatePrice(_) => {} - DocumentTransition::Purchase(_) => {} - } + let query = SingleDocumentDriveQuery { + contract_id: document_transition.data_contract_id().into_buffer(), + document_type_name: document_transition.document_type_name().clone(), + document_type_keeps_history: document_type.documents_keep_history(), + document_id: document_transition.base().id().into_buffer(), + block_time_ms: None, //None because we want latest + contested_status, + }; + let (root_hash, document) = + query.verify_proof(false, proof, document_type, platform_version)?; - let query = SingleDocumentDriveQuery { - contract_id: transition.data_contract_id().into_buffer(), - document_type_name: transition.document_type_name().clone(), - document_type_keeps_history: document_type.documents_keep_history(), - document_id: transition.base().id().into_buffer(), - block_time_ms: None, //None because we want latest - contested_status, - }; - let (root_hash, document) = - query.verify_proof(false, proof, document_type, platform_version)?; + match document_transition { + DocumentTransition::Create(create_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (create)", create_transition.base().id()))))?; + let expected_document = Document::try_from_create_transition( + create_transition, + documents_batch_transition.owner_id(), + block_info, + &document_type, + platform_version, + )?; - match transition { - DocumentTransition::Create(create_transition) => { - let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (create)", create_transition.base().id()))))?; - let expected_document = Document::try_from_create_transition( - create_transition, - documents_batch_transition.owner_id(), - block_info, - &document_type, - platform_version, - )?; + let transient_fields = document_type + .transient_fields() + .iter() + .map(|a| a.as_str()) + .collect(); - let transient_fields = document_type - .transient_fields() - .iter() - .map(|a| a.as_str()) - .collect(); + if !document.is_equal_ignoring_time_based_fields( + &expected_document, + Some(transient_fields), + platform_version, + )? { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document (time fields were not checked) after create with id {}", create_transition.base().id())))); + } + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([( + document.id(), + Some(document), + )])), + )) + } + DocumentTransition::Replace(replace_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (replace)", replace_transition.base().id()))))?; + let expected_document = Document::try_from_replace_transition( + replace_transition, + documents_batch_transition.owner_id(), + document.created_at(), //we can trust the created at (as we don't care) + document.created_at_block_height(), //we can trust the created at block height (as we don't care) + document.created_at_core_block_height(), //we can trust the created at core block height (as we don't care) + document.created_at(), //we can trust the created at (as we don't care) + document.created_at_block_height(), //we can trust the created at block height (as we don't care) + document.created_at_core_block_height(), //we can trust the created at core block height (as we don't care) + block_info, + &document_type, + platform_version, + )?; - if !document.is_equal_ignoring_time_based_fields( - &expected_document, - Some(transient_fields), - platform_version, - )? { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document (time fields were not checked) after create with id {}", create_transition.base().id())))); - } - Ok(( - root_hash, - VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), - )) - } - DocumentTransition::Replace(replace_transition) => { - let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (replace)", replace_transition.base().id()))))?; - let expected_document = Document::try_from_replace_transition( - replace_transition, - documents_batch_transition.owner_id(), - document.created_at(), //we can trust the created at (as we don't care) - document.created_at_block_height(), //we can trust the created at block height (as we don't care) - document.created_at_core_block_height(), //we can trust the created at core block height (as we don't care) - document.created_at(), //we can trust the created at (as we don't care) - document.created_at_block_height(), //we can trust the created at block height (as we don't care) - document.created_at_core_block_height(), //we can trust the created at core block height (as we don't care) - block_info, - &document_type, - platform_version, - )?; + let transient_fields = document_type + .transient_fields() + .iter() + .map(|a| a.as_str()) + .collect(); - let transient_fields = document_type - .transient_fields() - .iter() - .map(|a| a.as_str()) - .collect(); + if !document.is_equal_ignoring_time_based_fields( + &expected_document, + Some(transient_fields), + platform_version, + )? { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document (time fields were not checked) after replace with id {}", replace_transition.base().id())))); + } - if !document.is_equal_ignoring_time_based_fields( - &expected_document, - Some(transient_fields), - platform_version, - )? { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document (time fields were not checked) after replace with id {}", replace_transition.base().id())))); - } + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([( + document.id(), + Some(document), + )])), + )) + } + DocumentTransition::Transfer(transfer_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (transfer)", transfer_transition.base().id()))))?; + let recipient_owner_id = transfer_transition.recipient_owner_id(); - Ok(( - root_hash, - VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), - )) - } - DocumentTransition::Transfer(transfer_transition) => { - let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (transfer)", transfer_transition.base().id()))))?; - let recipient_owner_id = transfer_transition.recipient_owner_id(); + if document.owner_id() != recipient_owner_id { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not have the transfer executed after expected transfer with id {}", transfer_transition.base().id())))); + } - if document.owner_id() != recipient_owner_id { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not have the transfer executed after expected transfer with id {}", transfer_transition.base().id())))); - } + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([( + document.id(), + Some(document), + )])), + )) + } + DocumentTransition::Delete(delete_transition) => { + if document.is_some() { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution contained document after delete with id {}", delete_transition.base().id())))); + } + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([( + delete_transition.base().id(), + None, + )])), + )) + } + DocumentTransition::UpdatePrice(update_price_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (update price)", update_price_transition.base().id()))))?; + let new_document_price : Credits = document.properties().get_integer(PRICE).map_err(|e| Error::Proof(ProofError::IncorrectProof(format!("proof did not contain a document that contained a price field with id {} expected to exist because of state transition (update price): {}", update_price_transition.base().id(), e))))?; + if new_document_price != update_price_transition.price() { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document update of price after price update with id {}", update_price_transition.base().id())))); + } + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([( + document.id(), + Some(document), + )])), + )) + } + DocumentTransition::Purchase(purchase_transition) => { + let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (purchase)", purchase_transition.base().id()))))?; - Ok(( - root_hash, - VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), - )) - } - DocumentTransition::Delete(delete_transition) => { - if document.is_some() { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution contained document after delete with id {}", delete_transition.base().id())))); - } - Ok(( - root_hash, - VerifiedDocuments(BTreeMap::from([( - delete_transition.base().id(), - None, - )])), - )) - } - DocumentTransition::UpdatePrice(update_price_transition) => { - let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (update price)", update_price_transition.base().id()))))?; - let new_document_price : Credits = document.properties().get_integer(PRICE).map_err(|e| Error::Proof(ProofError::IncorrectProof(format!("proof did not contain a document that contained a price field with id {} expected to exist because of state transition (update price): {}", update_price_transition.base().id(), e))))?; - if new_document_price != update_price_transition.price() { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not contain expected document update of price after price update with id {}", update_price_transition.base().id())))); - } - Ok(( - root_hash, - VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), - )) - } - DocumentTransition::Purchase(purchase_transition) => { - let document = document.ok_or(Error::Proof(ProofError::IncorrectProof(format!("proof did not contain document with id {} expected to exist because of state transition (purchase)", purchase_transition.base().id()))))?; + if document.owner_id() != owner_id { + return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not have the transfer executed after expected transfer with id {}", purchase_transition.base().id())))); + } - if document.owner_id() != owner_id { - return Err(Error::Proof(ProofError::IncorrectProof(format!("proof of state transition execution did not have the transfer executed after expected transfer with id {}", purchase_transition.base().id())))); + Ok(( + root_hash, + VerifiedDocuments(BTreeMap::from([( + document.id(), + Some(document), + )])), + )) + } } - - Ok(( - root_hash, - VerifiedDocuments(BTreeMap::from([(document.id(), Some(document))])), - )) + } + BatchedTransitionRef::Token(token_transition) => { + todo!() + //todo + // we need to check if the contract has history + // if it has history we verify the proof of the history + // known_contracts_provider_fn + // let token_id = token_transition.token_id(); + // match token_transition { + // TokenTransition::Burn(_) => {} + // TokenTransition::Issuance(_) => {} + // TokenTransition::Transfer(_) => {} + // } } } } diff --git a/packages/rs-drive/src/verify/tokens/mod.rs b/packages/rs-drive/src/verify/tokens/mod.rs new file mode 100644 index 0000000000..9110a47eed --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/mod.rs @@ -0,0 +1,2 @@ +mod verify_token_balances_for_identity_ids; +mod verify_token_infos_for_identity_ids; diff --git a/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/mod.rs new file mode 100644 index 0000000000..6959213d81 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/mod.rs @@ -0,0 +1,80 @@ +mod v0; + +use crate::drive::Drive; +use dpp::balances::credits::TokenAmount; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the token balances for a set of identity IDs. + /// + /// This function checks the token balances of multiple identities by verifying the provided + /// proof against the specified token ID and identity IDs. It also supports verifying a subset + /// of a larger proof if necessary. + /// + /// # Parameters + /// + /// - `proof`: A byte slice representing the proof of authentication from the user. This is used + /// to verify the validity of the identity and its associated balance. + /// - `token_id`: A 32-byte array representing the unique identifier for the token whose balance + /// is being verified. + /// - `identity_ids`: A slice of 32-byte arrays, each representing a unique identity ID. These + /// are the identities whose token balances are being verified. + /// - `verify_subset_of_proof`: A boolean flag indicating whether the proof being verified is a + /// subset of a larger proof. If `true`, the verification will consider only a part of the proof. + /// - `platform_version`: The version of the platform against which the identity token balances are + /// being verified. This ensures compatibility with the correct API version. + /// + /// # Returns + /// + /// - `Result<(RootHash, BTreeMap<[u8; 32], Option>), Error>`: If the verification is successful: + /// - `RootHash`: The root hash of the GroveDB, representing the state of the database. + /// - `BTreeMap<[u8; 32], Option>`: A map of identity IDs to their associated token balances. + /// The `Option` can be `Some(TokenAmount)` if a balance exists or `None` if no balance is found. + /// + /// # Errors + /// + /// The function will return an `Error` if any of the following occur: + /// + /// - The provided authentication proof is invalid. + /// - The provided identity ID does not correspond to a valid balance. + /// - The provided platform version is unknown or unsupported. + /// + pub fn verify_token_balances_for_identity_ids< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .token + .verify_token_balances_for_identity_ids + { + 0 => Self::verify_token_balances_for_identity_ids_v0( + proof, + token_id, + identity_ids, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_token_balances_for_identity_ids".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/v0/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/v0/mod.rs new file mode 100644 index 0000000000..3bfa94f7a9 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_ids/v0/mod.rs @@ -0,0 +1,71 @@ +use crate::drive::Drive; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::balances::credits::TokenAmount; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_token_balances_for_identity_ids_v0< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Self::token_balances_for_identity_ids_query(token_id, identity_ids); + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + if proved_key_values.len() == identity_ids.len() { + let values = proved_key_values + .into_iter() + .map(|proved_key_value| { + let key: [u8; 32] = proved_key_value + .1 + .try_into() + .map_err(|_| Error::Proof(ProofError::IncorrectValueSize("value size")))?; + let maybe_element = proved_key_value.2; + match maybe_element { + None => Ok((key.into(), None)), + Some(element) => { + let balance: TokenAmount = element + .as_sum_item_value() + .map_err(Error::GroveDB)? + .try_into() + .map_err(|_| { + Error::Proof(ProofError::IncorrectValueSize( + "balance was negative", + )) + })?; + Ok((key.into(), Some(balance))) + } + } + }) + .collect::>()?; + Ok((root_hash, values)) + } else { + Err(Error::Proof(ProofError::WrongElementCount { + expected: identity_ids.len(), + got: proved_key_values.len(), + })) + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/mod.rs new file mode 100644 index 0000000000..b936762a97 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/mod.rs @@ -0,0 +1,79 @@ +mod v0; + +use crate::drive::Drive; +use dpp::tokens::info::IdentityTokenInfo; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the token infos for a set of identity IDs. + /// + /// This function checks the token infos of multiple identities by verifying the provided + /// proof against the specified token ID and identity IDs. It also supports verifying a subset + /// of a larger proof if necessary. + /// + /// # Parameters + /// + /// - `proof`: A byte slice representing the proof of authentication from the user. This is used + /// to verify the validity of the identity and its associated info. + /// - `token_id`: A 32-byte array representing the unique identifier for the token whose info + /// is being verified. + /// - `identity_ids`: A slice of 32-byte arrays, each representing a unique identity ID. These + /// are the identities whose token infos are being verified. + /// - `verify_subset_of_proof`: A boolean flag indicating whether the proof being verified is a + /// subset of a larger proof. If `true`, the verification will consider only a part of the proof. + /// - `platform_version`: The version of the platform against which the identity token infos are + /// being verified. This ensures compatibility with the correct API version. + /// + /// # Returns + /// + /// - `Result<(RootHash, BTreeMap<[u8; 32], Option>), Error>`: If the verification is successful: + /// - `RootHash`: The root hash of the GroveDB, representing the state of the database. + /// - `BTreeMap<[u8; 32], Option>`: A map of identity IDs to their associated token infos. + /// + /// # Errors + /// + /// The function will return an `Error` if any of the following occur: + /// + /// - The provided authentication proof is invalid. + /// - The provided identity ID does not correspond to a valid info. + /// - The provided platform version is unknown or unsupported. + /// + pub fn verify_token_infos_for_identity_ids< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .token + .verify_token_infos_for_identity_ids + { + 0 => Self::verify_token_infos_for_identity_ids_v0( + proof, + token_id, + identity_ids, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_token_infos_for_identity_ids".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/v0/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/v0/mod.rs new file mode 100644 index 0000000000..4c4a6092e4 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_ids/v0/mod.rs @@ -0,0 +1,65 @@ +use crate::drive::Drive; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::info::IdentityTokenInfo; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_token_infos_for_identity_ids_v0< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_id: [u8; 32], + identity_ids: &[[u8; 32]], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Self::token_infos_for_identity_ids_query(token_id, identity_ids); + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + if proved_key_values.len() == identity_ids.len() { + let values = proved_key_values + .into_iter() + .map(|proved_key_value| { + let key: [u8; 32] = proved_key_value + .1 + .try_into() + .map_err(|_| Error::Proof(ProofError::IncorrectValueSize("value size")))?; + let maybe_element = proved_key_value.2; + match maybe_element { + None => Ok((key.into(), None)), + Some(element) => { + let info_bytes = element.as_item_bytes().map_err(Error::GroveDB)?; + let info = IdentityTokenInfo::deserialize_from_bytes(info_bytes)?; + Ok((key.into(), Some(info))) + } + } + }) + .collect::>()?; + Ok((root_hash, values)) + } else { + Err(Error::Proof(ProofError::WrongElementCount { + expected: identity_ids.len(), + got: proved_key_values.len(), + })) + } + } +} diff --git a/packages/rs-drive/tests/deterministic_root_hash.rs b/packages/rs-drive/tests/deterministic_root_hash.rs index e2cd8cc75e..690fce9609 100644 --- a/packages/rs-drive/tests/deterministic_root_hash.rs +++ b/packages/rs-drive/tests/deterministic_root_hash.rs @@ -19,9 +19,11 @@ mod tests { /// Tests that the root hash is being calculated correctly after inserting empty subtrees into /// the root tree and the DPNS contract. - fn test_root_hash_with_batches(drive: &Drive, db_transaction: &Transaction) { - let platform_version = PlatformVersion::latest(); - + fn test_root_hash_with_batches( + drive: &Drive, + db_transaction: &Transaction, + platform_version: &PlatformVersion, + ) { // [1644293142180] INFO (35 on bf3bb2a2796a): createTree // path: [] // pathHash: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" @@ -297,20 +299,45 @@ mod tests { .unwrap() .expect("should return app hash"); - let expected_app_hash = "1b80f4a9f00597b3f1ddca904b3cee67576868adcdd802c0a3f91e14209bb402"; + // We expect a different app hash because data contract is not serialized the same way + let expected_app_hash = match platform_version.protocol_version { + 0..7 => "1b80f4a9f00597b3f1ddca904b3cee67576868adcdd802c0a3f91e14209bb402", + _ => "387fe8e2298bb33e0ff79fd377eccb14109fb2534c7338c535bd74b5b8580580", + }; assert_eq!(hex::encode(app_hash), expected_app_hash); } /// Runs `test_root_hash_with_batches` 10 times. #[test] - fn test_deterministic_root_hash_with_batches() { - let drive = setup_drive(None); + fn test_deterministic_root_hash_with_batches_first_platform_version() { + let drive = setup_drive(None, None); + + let platform_version = PlatformVersion::first(); + + let db_transaction = drive.grove.start_transaction(); + + for _ in 0..10 { + test_root_hash_with_batches(&drive, &db_transaction, platform_version); + + drive + .grove + .rollback_transaction(&db_transaction) + .expect("transaction should be rolled back"); + } + } + + /// Runs `test_root_hash_with_batches` 10 times. + #[test] + fn test_deterministic_root_hash_with_batches_latest_platform_version() { + let drive = setup_drive(None, None); + + let platform_version = PlatformVersion::latest(); let db_transaction = drive.grove.start_transaction(); for _ in 0..10 { - test_root_hash_with_batches(&drive, &db_transaction); + test_root_hash_with_batches(&drive, &db_transaction, platform_version); drive .grove diff --git a/packages/rs-drive/tests/query_tests.rs b/packages/rs-drive/tests/query_tests.rs index 6bad5144f9..8451908d68 100644 --- a/packages/rs-drive/tests/query_tests.rs +++ b/packages/rs-drive/tests/query_tests.rs @@ -196,10 +196,14 @@ impl PersonWithOptionalValues { #[cfg(feature = "server")] /// Inserts the test "family" contract and adds `count` documents containing randomly named people to it. -pub fn setup_family_tests(count: u32, seed: u64) -> (Drive, DataContract) { +pub fn setup_family_tests( + count: u32, + seed: u64, + platform_version: &PlatformVersion, +) -> (Drive, DataContract) { let drive_config = DriveConfig::default(); - let drive = setup_drive(Some(drive_config)); + let drive = setup_drive(Some(drive_config), None); let db_transaction = drive.grove.start_transaction(); @@ -208,8 +212,6 @@ pub fn setup_family_tests(count: u32, seed: u64) -> (Drive, DataContract) { add_init_contracts_structure_operations(&mut batch); - let platform_version = PlatformVersion::latest(); - drive .grove_apply_batch(batch, false, Some(&db_transaction), &platform_version.drive) .expect("expected to create contracts tree successfully"); @@ -219,7 +221,10 @@ pub fn setup_family_tests(count: u32, seed: u64) -> (Drive, DataContract) { &drive, "tests/supporting_files/contract/family/family-contract.json", None, + None, + None::, Some(&db_transaction), + Some(platform_version), ); let people = Person::random_people(count, seed); @@ -269,7 +274,7 @@ pub fn setup_family_tests(count: u32, seed: u64) -> (Drive, DataContract) { pub fn setup_family_tests_with_nulls(count: u32, seed: u64) -> (Drive, DataContract) { let drive_config = DriveConfig::default(); - let drive = setup_drive(Some(drive_config)); + let drive = setup_drive(Some(drive_config), None); let db_transaction = drive.grove.start_transaction(); @@ -289,7 +294,10 @@ pub fn setup_family_tests_with_nulls(count: u32, seed: u64) -> (Drive, DataContr &drive, "tests/supporting_files/contract/family/family-contract-fields-optional.json", None, + None, + None::, Some(&db_transaction), + None, ); let people = PersonWithOptionalValues::random_people(count, seed); @@ -338,7 +346,7 @@ pub fn setup_family_tests_with_nulls(count: u32, seed: u64) -> (Drive, DataContr pub fn setup_family_tests_only_first_name_index(count: u32, seed: u64) -> (Drive, DataContract) { let drive_config = DriveConfig::default(); - let drive = setup_drive(Some(drive_config)); + let drive = setup_drive(Some(drive_config), None); let db_transaction = drive.grove.start_transaction(); @@ -358,7 +366,10 @@ pub fn setup_family_tests_only_first_name_index(count: u32, seed: u64) -> (Drive &drive, "tests/supporting_files/contract/family/family-contract-only-first-name-index.json", None, + None, + None::, Some(&db_transaction), + None, ); let people = Person::random_people(count, seed); @@ -803,8 +814,9 @@ pub fn setup_dpns_tests_with_batches( count: u32, total_owners: Option, seed: u64, + platform_version: &PlatformVersion, ) -> (Drive, DataContract) { - let drive = setup_drive(Some(DriveConfig::default())); + let drive = setup_drive(Some(DriveConfig::default()), None); let db_transaction = drive.grove.start_transaction(); @@ -813,8 +825,6 @@ pub fn setup_dpns_tests_with_batches( add_init_contracts_structure_operations(&mut batch); - let platform_version = PlatformVersion::latest(); - drive .grove_apply_batch(batch, false, Some(&db_transaction), &platform_version.drive) .expect("expected to create contracts tree successfully"); @@ -824,7 +834,10 @@ pub fn setup_dpns_tests_with_batches( &drive, "tests/supporting_files/contract/dpns/dpns-contract.json", None, + None, + None::, Some(&db_transaction), + Some(platform_version), ); add_domains_to_contract( @@ -851,7 +864,7 @@ pub fn setup_withdrawal_tests( total_owners: Option, seed: u64, ) -> (Drive, DataContract) { - let drive = setup_drive(Some(DriveConfig::default())); + let drive = setup_drive(Some(DriveConfig::default()), None); let db_transaction = drive.grove.start_transaction(); @@ -871,7 +884,10 @@ pub fn setup_withdrawal_tests( &drive, "tests/supporting_files/contract/withdrawals/withdrawals-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); add_withdrawals_to_contract( @@ -894,7 +910,7 @@ pub fn setup_withdrawal_tests( #[cfg(feature = "server")] /// Sets up the References contract to test queries on. pub fn setup_references_tests(_count: u32, _seed: u64) -> (Drive, DataContract) { - let drive = setup_drive(Some(DriveConfig::default())); + let drive = setup_drive(Some(DriveConfig::default()), None); let db_transaction = drive.grove.start_transaction(); @@ -914,7 +930,10 @@ pub fn setup_references_tests(_count: u32, _seed: u64) -> (Drive, DataContract) &drive, "tests/supporting_files/contract/references/references_with_contract_history.json", None, + None, + None::, Some(&db_transaction), + None, ); drive @@ -929,7 +948,7 @@ pub fn setup_references_tests(_count: u32, _seed: u64) -> (Drive, DataContract) #[cfg(feature = "server")] /// Sets up and inserts random domain name data to the DPNS contract to test queries on. pub fn setup_dpns_tests_label_not_required(count: u32, seed: u64) -> (Drive, DataContract) { - let drive = setup_drive(Some(DriveConfig::default())); + let drive = setup_drive(Some(DriveConfig::default()), None); let db_transaction = drive.grove.start_transaction(); @@ -949,7 +968,10 @@ pub fn setup_dpns_tests_label_not_required(count: u32, seed: u64) -> (Drive, Dat &drive, "tests/supporting_files/contract/dpns/dpns-contract-label-not-required.json", None, + None, + None::, Some(&db_transaction), + None, ); add_domains_to_contract(&drive, &contract, Some(&db_transaction), count, None, seed); @@ -965,7 +987,7 @@ pub fn setup_dpns_tests_label_not_required(count: u32, seed: u64) -> (Drive, Dat #[cfg(feature = "server")] /// Sets up the DPNS contract and inserts data from the given path to test queries on. pub fn setup_dpns_test_with_data(path: &str) -> (Drive, DataContract) { - let drive = setup_drive(None); + let drive = setup_drive(None, None); let db_transaction = drive.grove.start_transaction(); @@ -984,7 +1006,10 @@ pub fn setup_dpns_test_with_data(path: &str) -> (Drive, DataContract) { &drive, "tests/supporting_files/contract/dpns/dpns-contract.json", None, + None, + None::, Some(&db_transaction), + None, ); let file = File::open(path).expect("should read domains from file"); @@ -1037,7 +1062,8 @@ pub fn setup_dpns_test_with_data(path: &str) -> (Drive, DataContract) { #[test] #[ignore] fn test_query_many() { - let (drive, contract) = setup_family_tests(1600, 73509); + let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup_family_tests(1600, 73509, platform_version); let db_transaction = drive.grove.start_transaction(); let platform_version = PlatformVersion::latest(); @@ -1081,107 +1107,1442 @@ fn test_query_many() { .expect("transaction should be committed"); } -#[cfg(feature = "server")] -#[test] -fn test_reference_proof_single_index() { - let (drive, contract) = setup_family_tests_only_first_name_index(1, 73509); +#[cfg(feature = "server")] +#[test] +fn test_reference_proof_single_index() { + let (drive, contract) = setup_family_tests_only_first_name_index(1, 73509); + + let platform_version = PlatformVersion::latest(); + + let db_transaction = drive.grove.start_transaction(); + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + + // A query getting all elements by firstName + + let query_value = json!({ + "where": [ + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) + .expect("proof should be executed"); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); +} + +#[cfg(feature = "server")] +#[test] +fn test_non_existence_reference_proof_single_index() { + let (drive, contract) = setup_family_tests_only_first_name_index(0, 73509); + + let platform_version = PlatformVersion::latest(); + + let db_transaction = drive.grove.start_transaction(); + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + + // A query getting all elements by firstName + + let query_value = json!({ + "where": [ + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) + .expect("proof should be executed"); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); +} + +#[cfg(feature = "server")] +#[test] +fn test_family_basic_queries_first_version() { + let platform_version = PlatformVersion::first(); + let (drive, contract) = setup_family_tests(10, 73509, platform_version); + + let db_transaction = drive.grove.start_transaction(); + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + + let expected_app_hash = vec![ + 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, + 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, + ]; + + assert_eq!(root_hash.as_slice(), expected_app_hash); + + let all_names = [ + "Adey".to_string(), + "Briney".to_string(), + "Cammi".to_string(), + "Celinda".to_string(), + "Dalia".to_string(), + "Gilligan".to_string(), + "Kevina".to_string(), + "Meta".to_string(), + "Noellyn".to_string(), + "Prissie".to_string(), + ]; + + // A query getting all elements by firstName + + let query_value = json!({ + "where": [ + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + assert_eq!(names, all_names); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name is Adey (which should exist) + let query_value = json!({ + "where": [ + ["firstName", "==", "Adey"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(results.len(), 1); + + let (proof_root_hash, proof_results, _) = drive + .query_proof_of_documents_using_cbor_encoded_query_only_get_elements( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name is Adey and lastName Randolf + + let query_value = json!({ + "where": [ + ["firstName", "==", "Adey"], + ["lastName", "==", "Randolf"] + ], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let (proof_root_hash, proof_results, _) = drive + .query_proof_of_documents_using_cbor_encoded_query_only_get_elements( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + let document = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize from bytes"); + let last_name = document + .get("lastName") + .expect("we should be able to get the last name") + .as_text() + .expect("last name must be a string"); + + assert_eq!(last_name, "Randolf"); + + // A query getting all people who's first name is in a range with a single element Adey, + // order by lastName (this should exist) + + let query_value = json!({ + "where": [ + ["firstName", "in", ["Adey"]] + ], + "orderBy": [ + ["firstName", "asc"], + ["lastName", "asc"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let (proof_root_hash, proof_results, _) = drive + .query_proof_of_documents_using_cbor_encoded_query_only_get_elements( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name is Adey, order by lastName (which should exist) + + let query_value = json!({ + "where": [ + ["firstName", "==", "Adey"] + ], + "orderBy": [ + ["lastName", "asc"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let (proof_root_hash, proof_results, _) = drive + .query_proof_of_documents_using_cbor_encoded_query_only_get_elements( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + let document = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize from bytes"); + let last_name = document + .get("lastName") + .expect("we should be able to get the last name") + .as_text() + .expect("last name must be a string"); + + assert_eq!(last_name, "Randolf"); + + // A query getting all people who's first name is Chris (which is not exist) + + let query_value = json!({ + "where": [ + ["firstName", "==", "Chris"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 0); + + let (proof_root_hash, proof_results, _) = drive + .query_proof_of_documents_using_cbor_encoded_query_only_get_elements( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting a middle name + + let query_value = json!({ + "where": [ + ["middleName", "==", "Briggs"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let (proof_root_hash, proof_results, _) = drive + .query_proof_of_documents_using_cbor_encoded_query_only_get_elements( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name is before Chris + + let query_value = json!({ + "where": [ + ["firstName", "<", "Chris"] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_names_before_chris = [ + "Adey".to_string(), + "Briney".to_string(), + "Cammi".to_string(), + "Celinda".to_string(), + ]; + assert_eq!(names, expected_names_before_chris); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name starts with C + + let query_value = json!({ + "where": [ + ["firstName", "StartsWith", "C"] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_names_starting_with_c = ["Cammi".to_string(), "Celinda".to_string()]; + assert_eq!(names, expected_names_starting_with_c); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name starts with C, but limit to 1 and be descending + + let query_value = json!({ + "where": [ + ["firstName", "StartsWith", "C"] + ], + "limit": 1, + "orderBy": [ + ["firstName", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_names_starting_with_c_desc_1 = ["Celinda".to_string()]; + assert_eq!(names, expected_names_starting_with_c_desc_1); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting all people who's first name is between Chris and Noellyn included + + let query_value = json!({ + "where": [ + ["firstName", ">", "Chris"], + ["firstName", "<=", "Noellyn"] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + assert_eq!(results.len(), 5); + + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_between_names = [ + "Dalia".to_string(), + "Gilligan".to_string(), + "Kevina".to_string(), + "Meta".to_string(), + "Noellyn".to_string(), + ]; + + assert_eq!(names, expected_between_names); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting back elements having specific names + + let query_value = json!({ + "where": [ + ["firstName", "in", names] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + assert_eq!(names, expected_between_names); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + let query_value = json!({ + "where": [ + ["firstName", "in", names] + ], + "limit": 100, + "orderBy": [ + ["firstName", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_reversed_between_names = [ + "Noellyn".to_string(), + "Meta".to_string(), + "Kevina".to_string(), + "Gilligan".to_string(), + "Dalia".to_string(), + ]; + + assert_eq!(names, expected_reversed_between_names); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting back elements having specific names and over a certain age + + let query_value = json!({ + "where": [ + ["firstName", "in", names], + ["age", ">=", 45] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"], + ["age", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_names_45_over = [ + "Dalia".to_string(), + "Gilligan".to_string(), + "Kevina".to_string(), + "Meta".to_string(), + ]; + + assert_eq!(names, expected_names_45_over); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + // A query getting back elements having specific names and over a certain age + + let query_value = json!({ + "where": [ + ["firstName", "in", names], + ["age", ">", 48] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"], + ["age", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + // Kevina is 48 so she should be now excluded, Dalia is 68, Gilligan is 49 and Meta is 59 + + let expected_names_over_48 = [ + "Dalia".to_string(), + "Gilligan".to_string(), + "Meta".to_string(), + ]; + + assert_eq!(names, expected_names_over_48); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); + + let ages: HashMap = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let name = name_value + .as_text() + .expect("the first name should be a string") + .to_string(); + let age_value = document + .get("age") + .expect("we should be able to get the age"); + let age: u8 = age_value.to_integer().expect("expected u8 value"); + (name, age) + }) + .collect(); + + let meta_age = ages + .get("Meta") + .expect("we should be able to get Kevina as she is 48"); + + assert_eq!(*meta_age, 59); + + // fetching by $id + let mut rng = rand::rngs::StdRng::seed_from_u64(84594); + let id_bytes = bs58::decode("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD") + .into_vec() + .expect("this should decode"); + + let owner_id_bytes = bs58::decode("BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj") + .into_vec() + .expect("this should decode"); + + let fixed_person = Person { + id: id_bytes, + owner_id: owner_id_bytes, + first_name: String::from("Wisdom"), + middle_name: String::from("Madabuchukwu"), + last_name: String::from("Ogwu"), + age: rng.gen_range(0..85), + }; + let serialized_person = serde_json::to_value(fixed_person).expect("serialized person"); + let person_cbor = cbor_serializer::serializable_value_to_cbor(&serialized_person, Some(0)) + .expect("expected to serialize to cbor"); + let document = Document::from_cbor(person_cbor.as_slice(), None, None, platform_version) + .expect("document should be properly deserialized"); + + let document_type = contract + .document_type_for_name("person") + .expect("expected to get document type"); + + let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0))); + + drive + .add_document_for_contract( + DocumentAndContractInfo { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentRefInfo((&document, storage_flags)), + owner_id: None, + }, + contract: &contract, + document_type, + }, + true, + BlockInfo::genesis(), + true, + Some(&db_transaction), + platform_version, + None, + ) + .expect("document should be inserted"); + + let id_two_bytes = bs58::decode("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179") + .into_vec() + .expect("should decode"); + let owner_id_bytes = bs58::decode("Di8dtJXv3L2YnzDNUN4w5rWLPSsSAzv6hLMMQbg3eyVA") + .into_vec() + .expect("this should decode"); + let next_person = Person { + id: id_two_bytes, + owner_id: owner_id_bytes, + first_name: String::from("Wdskdfslgjfdlj"), + middle_name: String::from("Mdsfdsgsdl"), + last_name: String::from("dkfjghfdk"), + age: rng.gen_range(0..85), + }; + let serialized_person = serde_json::to_value(next_person).expect("serialized person"); + let person_cbor = cbor_serializer::serializable_value_to_cbor(&serialized_person, Some(0)) + .expect("expected to serialize to cbor"); + let document = Document::from_cbor(person_cbor.as_slice(), None, None, platform_version) + .expect("document should be properly deserialized"); + + let document_type = contract + .document_type_for_name("person") + .expect("expected to get document type"); + + let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0))); + + drive + .add_document_for_contract( + DocumentAndContractInfo { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentRefInfo((&document, storage_flags)), + owner_id: None, + }, + contract: &contract, + document_type, + }, + true, + BlockInfo::genesis(), + true, + Some(&db_transaction), + platform_version, + None, + ) + .expect("document should be inserted"); + + let query_value = json!({ + "where": [ + ["$id", "in", vec![String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // TODO: Add test for proofs after transaction + // drive.grove.commit_transaction(db_transaction).expect("unable to commit transaction"); + // let (proof_root_hash, proof_results) = drive + // .query_documents_from_contract_as_grove_proof_only_get_elements( + // &contract, + // person_document_type, + // query_cbor.as_slice(), + // None, + // ) + // .expect("query should be executed"); + // assert_eq!(root_hash, proof_root_hash); + // assert_eq!(results, proof_results); + // let db_transaction = drive.grove.start_transaction(); + + // fetching by $id with order by + + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + "orderBy": [["$id", "asc"]], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 2); + + let last_person = Document::from_bytes( + results.first().unwrap().as_slice(), + document_type, + platform_version, + ) + .expect("we should be able to deserialize the document"); + + assert_eq!( + last_person.id().to_vec(), + vec![ + 76, 161, 17, 201, 152, 232, 129, 48, 168, 13, 49, 10, 218, 53, 118, 136, 165, 198, 189, + 116, 116, 22, 133, 92, 104, 165, 186, 249, 94, 81, 45, 20, + ] + ); + + // fetching by $id with order by desc + + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + "orderBy": [["$id", "desc"]], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 2); + + let last_person = Document::from_bytes( + results.first().unwrap().as_slice(), + document_type, + platform_version, + ) + .expect("we should be able to deserialize the document"); + + assert_eq!( + last_person.id().to_vec(), + vec![ + 140, 161, 17, 201, 152, 232, 129, 48, 168, 13, 49, 10, 218, 53, 118, 136, 165, 198, + 189, 116, 116, 22, 133, 92, 104, 165, 186, 249, 94, 81, 45, 20, + ] + ); + + // + // // fetching with empty where and orderBy + // + let query_value = json!({}); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 12); + + // + // // fetching with empty where and orderBy $id desc + // + let query_value = json!({ + "orderBy": [["$id", "desc"]] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 12); + + let last_person = Document::from_bytes( + results.first().unwrap().as_slice(), + document_type, + platform_version, + ) + .expect("we should be able to deserialize the document"); + + assert_eq!( + last_person.id().to_vec(), + vec![ + 249, 170, 70, 122, 181, 31, 35, 176, 175, 131, 70, 150, 250, 223, 194, 203, 175, 200, + 107, 252, 199, 227, 154, 105, 89, 57, 38, 85, 236, 192, 254, 88, + ] + ); + + // + // // fetching with ownerId in a set of values + // + let query_value = json!({ + "where": [ + ["$ownerId", "in", ["BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj", "Di8dtJXv3L2YnzDNUN4w5rWLPSsSAzv6hLMMQbg3eyVA"]] + ], + "orderBy": [["$ownerId", "desc"]] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 2); + + // + // // fetching with ownerId equal and orderBy + // + let query_value = json!({ + "where": [ + ["$ownerId", "==", "BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj"] + ], + "orderBy": [["$ownerId", "asc"]] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // query empty contract with nested path queries + + let dashpay_contract = json_document_to_contract( + "tests/supporting_files/contract/dashpay/dashpay-contract.json", + false, + platform_version, + ) + .expect("expected to get cbor document"); + + drive + .apply_contract( + &dashpay_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + let query_value = json!({ + "where": [ + ["$ownerId", "==", "BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj"], + ["toUserId", "==", "BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj"], + ], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &dashpay_contract, + dashpay_contract + .document_type_for_name("contactRequest") + .expect("should have contact document type"), + &query_cbor, + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 0); - let platform_version = PlatformVersion::latest(); + // using non existing document in startAt - let db_transaction = drive.grove.start_transaction(); + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("5A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF178")]], + ], + "orderBy": [["$id", "asc"]], + }); - let root_hash = drive - .grove - .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) - .unwrap() - .expect("there is always a root hash"); + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); - // A query getting all elements by firstName + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // using non existing document in startAt let query_value = json!({ "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], ], - "limit": 100, - "orderBy": [ - ["firstName", "asc"] - ] + "startAt": String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF178"), + "orderBy": [["$id", "asc"]], }); - let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) .expect("expected to serialize to cbor"); + let person_document_type = contract .document_type_for_name("person") .expect("contract should have a person document type"); - let query = DriveDocumentQuery::from_cbor( - where_cbor.as_slice(), + + let result = drive.query_documents_cbor_from_contract( &contract, person_document_type, - &drive.config, - ) - .expect("query should be built"); - let (results, _, _) = query - .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) - .expect("proof should be executed"); - - let (proof_root_hash, proof_results, _) = query - .execute_with_proof_only_get_elements(&drive, None, None, platform_version) - .expect("we should be able to a proof"); - assert_eq!(root_hash, proof_root_hash); - assert_eq!(results, proof_results); -} - -#[cfg(feature = "server")] -#[test] -fn test_non_existence_reference_proof_single_index() { - let (drive, contract) = setup_family_tests_only_first_name_index(0, 73509); - - let platform_version = PlatformVersion::latest(); - - let db_transaction = drive.grove.start_transaction(); + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ); - let root_hash = drive - .grove - .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) - .unwrap() - .expect("there is always a root hash"); + assert!( + matches!(result, Err(Error::Query(QuerySyntaxError::StartDocumentNotFound(message))) if message == "startAt document not found") + ); - // A query getting all elements by firstName + // using non existing document in startAfter let query_value = json!({ "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], ], - "limit": 100, - "orderBy": [ - ["firstName", "asc"] - ] + "startAfter": String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF178"), + "orderBy": [["$id", "asc"]], }); - let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) .expect("expected to serialize to cbor"); + let person_document_type = contract .document_type_for_name("person") .expect("contract should have a person document type"); - let query = DriveDocumentQuery::from_cbor( - where_cbor.as_slice(), + + let result = drive.query_documents_cbor_from_contract( &contract, person_document_type, - &drive.config, - ) - .expect("query should be built"); - let (results, _, _) = query - .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) - .expect("proof should be executed"); + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ); - let (proof_root_hash, proof_results, _) = query - .execute_with_proof_only_get_elements(&drive, None, None, platform_version) - .expect("we should be able to a proof"); - assert_eq!(root_hash, proof_root_hash); - assert_eq!(results, proof_results); + assert!( + matches!(result, Err(Error::Query(QuerySyntaxError::StartDocumentNotFound(message))) if message == "startAfter document not found") + ); + + // validate eventual root hash + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + + assert_eq!( + root_hash.as_slice(), + vec![ + 251, 69, 177, 93, 128, 236, 106, 87, 205, 123, 80, 61, 44, 107, 186, 193, 22, 192, 239, + 7, 107, 110, 97, 197, 59, 245, 26, 12, 63, 91, 248, 231 + ], + ); } #[cfg(feature = "server")] #[test] fn test_family_basic_queries() { - let (drive, contract) = setup_family_tests(10, 73509); let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup_family_tests(10, 73509, platform_version); let db_transaction = drive.grove.start_transaction(); @@ -1192,8 +2553,8 @@ fn test_family_basic_queries() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, - 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, + 63, 90, 74, 129, 70, 204, 232, 67, 190, 85, 133, 79, 254, 245, 203, 180, 77, 67, 94, 22, + 180, 99, 51, 251, 82, 117, 211, 14, 136, 51, 228, 177, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -2506,8 +3867,8 @@ fn test_family_basic_queries() { assert_eq!( root_hash.as_slice(), vec![ - 251, 69, 177, 93, 128, 236, 106, 87, 205, 123, 80, 61, 44, 107, 186, 193, 22, 192, 239, - 7, 107, 110, 97, 197, 59, 245, 26, 12, 63, 91, 248, 231, + 187, 202, 114, 108, 228, 21, 246, 191, 11, 30, 112, 178, 38, 36, 145, 109, 238, 11, + 210, 210, 0, 227, 175, 151, 149, 166, 143, 15, 144, 255, 82, 229, ], ); } @@ -2515,9 +3876,8 @@ fn test_family_basic_queries() { #[cfg(feature = "server")] #[test] fn test_family_person_update() { - let (drive, contract) = setup_family_tests(10, 73509); - let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup_family_tests(10, 73509, platform_version); let epoch_change_fee_version_test: Lazy = Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); @@ -2645,9 +4005,8 @@ fn test_family_person_update() { #[cfg(feature = "server")] #[test] fn test_family_starts_at_queries() { - let (drive, contract) = setup_family_tests(10, 73509); - let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup_family_tests(10, 73509, platform_version); let db_transaction = drive.grove.start_transaction(); @@ -2658,8 +4017,8 @@ fn test_family_starts_at_queries() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, - 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, + 63, 90, 74, 129, 70, 204, 232, 67, 190, 85, 133, 79, 254, 245, 203, 180, 77, 67, 94, 22, + 180, 99, 51, 251, 82, 117, 211, 14, 136, 51, 228, 177, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -2908,10 +4267,11 @@ fn test_family_starts_at_queries() { #[cfg(feature = "server")] #[test] fn test_family_sql_query() { + let platform_version = PlatformVersion::latest(); // These helpers confirm that sql statements produce the same drive query // as their json counterparts, helpers above confirm that the json queries // produce the correct result set - let (drive, contract) = setup_family_tests(10, 73509); + let (drive, contract) = setup_family_tests(10, 73509, platform_version); let person_document_type = contract .document_type_for_name("person") .expect("contract should have a person document type"); @@ -3109,8 +4469,8 @@ fn test_family_with_nulls_query() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 92, 186, 224, 49, 242, 195, 32, 14, 46, 55, 244, 57, 55, 191, 10, 119, 228, 132, 91, 235, - 170, 114, 36, 41, 126, 136, 180, 51, 132, 17, 26, 182, + 144, 185, 8, 30, 191, 97, 149, 182, 117, 203, 98, 187, 156, 93, 168, 171, 134, 112, 221, + 230, 249, 131, 86, 1, 26, 92, 242, 25, 251, 187, 192, 182, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3219,9 +4579,8 @@ fn test_family_with_nulls_query() { #[cfg(feature = "server")] #[test] fn test_query_with_cached_contract() { - let (drive, contract) = setup_family_tests(10, 73509); - let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup_family_tests(10, 73509, platform_version); let db_transaction = drive.grove.start_transaction(); @@ -3233,8 +4592,8 @@ fn test_query_with_cached_contract() { // Make sure the state is deterministic let expected_app_hash = vec![ - 32, 210, 24, 196, 148, 43, 20, 34, 0, 116, 183, 136, 32, 210, 163, 183, 214, 6, 152, 86, - 46, 45, 88, 13, 23, 41, 37, 70, 129, 119, 211, 12, + 63, 90, 74, 129, 70, 204, 232, 67, 190, 85, 133, 79, 254, 245, 203, 180, 77, 67, 94, 22, + 180, 99, 51, 251, 82, 117, 211, 14, 136, 51, 228, 177, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -3292,9 +4651,8 @@ fn test_query_with_cached_contract() { #[cfg(feature = "server")] #[test] fn test_dpns_query_contract_verification() { - let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456); - let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, platform_version); let root_hash = drive .grove @@ -3368,10 +4726,9 @@ fn test_contract_keeps_history_fetch_and_verification() { #[cfg(feature = "server")] #[test] -fn test_dpns_query() { - let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456); - - let platform_version = PlatformVersion::latest(); +fn test_dpns_query_first_version() { + let platform_version = PlatformVersion::first(); + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, &platform_version); let db_transaction = drive.grove.start_transaction(); @@ -3919,9 +5276,10 @@ fn test_dpns_insertion_with_aliases() { #[cfg(feature = "server")] #[test] -fn test_dpns_query_start_at() { +fn test_dpns_query_start_at_first_version() { + let platform_version = PlatformVersion::first(); // The point of this test is to test the situation where we have a start at a certain value for the DPNS query. - let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456); + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, platform_version); let platform_version = PlatformVersion::latest(); @@ -4011,11 +5369,107 @@ fn test_dpns_query_start_at() { assert_eq!(results, proof_results); } +#[cfg(feature = "server")] +#[test] +fn test_dpns_query_start_at_latest_version() { + let platform_version = PlatformVersion::latest(); + // The point of this test is to test the situation where we have a start at a certain value for the DPNS query. + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, platform_version); + + let platform_version = PlatformVersion::latest(); + + let db_transaction = drive.grove.start_transaction(); + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + + let expected_app_hash = vec![ + 248, 74, 104, 110, 129, 228, 194, 1, 4, 239, 134, 54, 105, 172, 221, 43, 101, 133, 235, + 146, 182, 153, 212, 118, 189, 99, 227, 14, 94, 83, 17, 98, + ]; + + assert_eq!(root_hash.as_slice(), expected_app_hash,); + + // let all_names = [ + // "amalle".to_string(), + // "anna-diane".to_string(), + // "atalanta".to_string(), + // "eden".to_string(), + // "laureen".to_string(), + // "leone".to_string(), + // "marilyn".to_string(), + // "minna".to_string(), + // "mora".to_string(), + // "phillie".to_string(), + // ]; + + // A query getting one element starting with a in dash parent domain asc + + let anna_id = hex::decode("0e97eb86ceca4309751616089336a127a5d48282712473b2d0fc5663afb1a080") + .expect("expected to decode id"); + let encoded_start_at = bs58::encode(anna_id).into_string(); + + let query_value = json!({ + "where": [ + ["normalizedParentDomainName", "==", "dash"] + ], + "startAt": encoded_start_at, + "limit": 1, + "orderBy": [ + ["normalizedLabel", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let domain_document_type = contract + .document_type_for_name("domain") + .expect("contract should have a domain document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + domain_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), domain_document_type, platform_version) + .expect("we should be able to deserialize the document"); + let normalized_label_value = document + .get("normalizedLabel") + .expect("we should be able to get the first name"); + let normalized_label = normalized_label_value + .as_text() + .expect("the normalized label should be a string"); + String::from(normalized_label) + }) + .collect(); + + let a_names = ["anna-diane".to_string()]; + + assert_eq!(names, a_names); + + let (proof_root_hash, proof_results, _) = query + .execute_with_proof_only_get_elements(&drive, None, None, platform_version) + .expect("we should be able to a proof"); + assert_eq!(root_hash, proof_root_hash); + assert_eq!(results, proof_results); +} + #[cfg(feature = "server")] #[test] fn test_dpns_query_start_after() { + let platform_version = PlatformVersion::latest(); // The point of this test is to test the situation where we have a start at a certain value for the DPNS query. - let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456); + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, platform_version); let platform_version = PlatformVersion::latest(); @@ -4028,8 +5482,8 @@ fn test_dpns_query_start_after() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, - 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, + 248, 74, 104, 110, 129, 228, 194, 1, 4, 239, 134, 54, 105, 172, 221, 43, 101, 133, 235, + 146, 182, 153, 212, 118, 189, 99, 227, 14, 94, 83, 17, 98, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4108,8 +5562,9 @@ fn test_dpns_query_start_after() { #[cfg(feature = "server")] #[test] fn test_dpns_query_start_at_desc() { + let platform_version = PlatformVersion::latest(); // The point of this test is to test the situation where we have a start at a certain value for the DPNS query. - let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456); + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, platform_version); let platform_version = PlatformVersion::latest(); @@ -4122,8 +5577,8 @@ fn test_dpns_query_start_at_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, - 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, + 248, 74, 104, 110, 129, 228, 194, 1, 4, 239, 134, 54, 105, 172, 221, 43, 101, 133, 235, + 146, 182, 153, 212, 118, 189, 99, 227, 14, 94, 83, 17, 98, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4202,8 +5657,9 @@ fn test_dpns_query_start_at_desc() { #[cfg(feature = "server")] #[test] fn test_dpns_query_start_after_desc() { + let platform_version = PlatformVersion::latest(); // The point of this test is to test the situation where we have a start at a certain value for the DPNS query. - let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456); + let (drive, contract) = setup_dpns_tests_with_batches(10, None, 11456, platform_version); let platform_version = PlatformVersion::latest(); @@ -4216,8 +5672,8 @@ fn test_dpns_query_start_after_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 142, 246, 25, 166, 52, 184, 158, 102, 192, 111, 173, 255, 155, 125, 53, 233, 98, 241, 201, - 233, 2, 58, 47, 90, 209, 207, 147, 204, 83, 68, 183, 143, + 248, 74, 104, 110, 129, 228, 194, 1, 4, 239, 134, 54, 105, 172, 221, 43, 101, 133, 235, + 146, 182, 153, 212, 118, 189, 99, 227, 14, 94, 83, 17, 98, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4410,8 +5866,8 @@ fn test_dpns_query_start_at_with_null_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 72, 138, 172, 70, 225, 95, 64, 122, 142, 96, 131, 223, 154, 119, 132, 79, 182, 97, 202, 63, - 120, 116, 39, 217, 25, 208, 176, 49, 242, 138, 67, 112, + 11, 67, 98, 193, 214, 56, 66, 244, 193, 131, 252, 190, 5, 52, 29, 96, 160, 27, 222, 78, 91, + 150, 54, 85, 81, 249, 14, 74, 213, 181, 254, 120, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4615,8 +6071,8 @@ fn test_dpns_query_start_after_with_null_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 72, 138, 172, 70, 225, 95, 64, 122, 142, 96, 131, 223, 154, 119, 132, 79, 182, 97, 202, 63, - 120, 116, 39, 217, 25, 208, 176, 49, 242, 138, 67, 112, + 11, 67, 98, 193, 214, 56, 66, 244, 193, 131, 252, 190, 5, 52, 29, 96, 160, 27, 222, 78, 91, + 150, 54, 85, 81, 249, 14, 74, 213, 181, 254, 120, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -4823,8 +6279,8 @@ fn test_dpns_query_start_after_with_null_id_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 72, 138, 172, 70, 225, 95, 64, 122, 142, 96, 131, 223, 154, 119, 132, 79, 182, 97, 202, 63, - 120, 116, 39, 217, 25, 208, 176, 49, 242, 138, 67, 112, + 11, 67, 98, 193, 214, 56, 66, 244, 193, 131, 252, 190, 5, 52, 29, 96, 160, 27, 222, 78, 91, + 150, 54, 85, 81, 249, 14, 74, 213, 181, 254, 120, ]; assert_eq!(root_hash.as_slice(), expected_app_hash,); @@ -5036,8 +6492,8 @@ fn test_withdrawals_query_by_owner_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 144, 177, 24, 41, 104, 174, 220, 135, 164, 0, 240, 215, 42, 60, 249, 142, 150, 169, 135, - 72, 151, 35, 238, 131, 164, 229, 106, 83, 198, 109, 65, 211, + 27, 172, 224, 121, 173, 248, 170, 255, 202, 209, 7, 83, 203, 185, 208, 102, 157, 75, 55, + 21, 217, 212, 91, 174, 144, 146, 135, 92, 97, 156, 166, 6, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -5116,8 +6572,8 @@ fn test_withdrawals_query_start_after_query_by_owner_id() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 144, 177, 24, 41, 104, 174, 220, 135, 164, 0, 240, 215, 42, 60, 249, 142, 150, 169, 135, - 72, 151, 35, 238, 131, 164, 229, 106, 83, 198, 109, 65, 211, + 27, 172, 224, 121, 173, 248, 170, 255, 202, 209, 7, 83, 203, 185, 208, 102, 157, 75, 55, + 21, 217, 212, 91, 174, 144, 146, 135, 92, 97, 156, 166, 6, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); @@ -5217,8 +6673,8 @@ fn test_withdrawals_query_start_after_query_by_owner_id_desc() { .expect("there is always a root hash"); let expected_app_hash = vec![ - 144, 177, 24, 41, 104, 174, 220, 135, 164, 0, 240, 215, 42, 60, 249, 142, 150, 169, 135, - 72, 151, 35, 238, 131, 164, 229, 106, 83, 198, 109, 65, 211, + 27, 172, 224, 121, 173, 248, 170, 255, 202, 209, 7, 83, 203, 185, 208, 102, 157, 75, 55, + 21, 217, 212, 91, 174, 144, 146, 135, 92, 97, 156, 166, 6, ]; assert_eq!(root_hash.as_slice(), expected_app_hash); diff --git a/packages/rs-drive/tests/query_tests_history.rs b/packages/rs-drive/tests/query_tests_history.rs index c14dfeca9e..1aa1b98fe4 100644 --- a/packages/rs-drive/tests/query_tests_history.rs +++ b/packages/rs-drive/tests/query_tests_history.rs @@ -161,15 +161,14 @@ pub fn setup( count: usize, restrict_to_inserts: Option>, seed: u64, + platform_version: &PlatformVersion, ) -> (Drive, DataContract) { let drive_config = DriveConfig::default(); - let platform_version = PlatformVersion::latest(); - let epoch_change_fee_version_test: Lazy = Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); - let drive = setup_drive(Some(drive_config)); + let drive = setup_drive(Some(drive_config), None); let db_transaction = drive.grove.start_transaction(); @@ -187,7 +186,10 @@ pub fn setup( &drive, "tests/supporting_files/contract/family/family-contract-with-history.json", None, + None, + None::, Some(&db_transaction), + Some(platform_version), ); let block_times: Vec = vec![0, 15, 100, 1000]; @@ -250,15 +252,15 @@ pub fn setup( #[test] fn test_setup() { let range_inserts = vec![0, 2]; - setup(10, Some(range_inserts), 73509); + let platform_version = PlatformVersion::latest(); + setup(10, Some(range_inserts), 73509, platform_version); } #[cfg(feature = "server")] #[test] -fn test_query_historical() { - let (drive, contract) = setup(10, None, 73509); - - let platform_version = PlatformVersion::latest(); +fn test_query_historical_first_platform_version() { + let platform_version = PlatformVersion::first(); + let (drive, contract) = setup(10, None, 73509, platform_version); let epoch_change_fee_version_test: Lazy = Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); @@ -1644,3 +1646,1394 @@ fn test_query_historical() { ] ); } + +#[cfg(feature = "server")] +#[test] +fn test_query_historical_latest_platform_version() { + let platform_version = PlatformVersion::latest(); + let (drive, contract) = setup(10, None, 73509, platform_version); + + let epoch_change_fee_version_test: Lazy = + Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())])); + + let db_transaction = drive.grove.start_transaction(); + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + assert_eq!( + root_hash.as_slice(), + vec![ + 5, 227, 59, 163, 38, 58, 181, 91, 23, 56, 47, 52, 138, 63, 5, 54, 205, 249, 205, 225, + 78, 225, 195, 2, 104, 6, 11, 77, 56, 69, 113, 237, + ] + ); + + let all_names = [ + "Adey".to_string(), + "Briney".to_string(), + "Cammi".to_string(), + "Celinda".to_string(), + "Dalia".to_string(), + "Gilligan".to_string(), + "Kevina".to_string(), + "Meta".to_string(), + "Noellyn".to_string(), + "Prissie".to_string(), + ]; + + // A query getting all elements by firstName + + let query_value = json!({ + "where": [ + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, Some(&db_transaction), platform_version) + .expect("proof should be executed"); + let names: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + assert_eq!(names, all_names); + + // A query getting all people who's first name is Chris (which should exist) + + let query_value = json!({ + "where": [ + ["firstName", "==", "Adey"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // A query getting all people who's first name is Adey and lastName Randolf + + let query_value = json!({ + "where": [ + ["firstName", "==", "Adey"], + ["lastName", "==", "Randolf"] + ], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let document = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize the cbor"); + let last_name = document + .get("lastName") + .expect("we should be able to get the last name") + .as_text() + .expect("last name must be a string"); + + assert_eq!(last_name, "Randolf"); + + // A query getting all people who's first name is in a range with a single element Adey, + // order by lastName (this should exist) + + let query_value = json!({ + "where": [ + ["firstName", "in", ["Adey"]] + ], + "orderBy": [ + ["firstName", "asc"], + ["lastName", "asc"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // A query getting all people who's first name is Adey, order by lastName (which should exist) + + let query_value = json!({ + "where": [ + ["firstName", "==", "Adey"] + ], + "orderBy": [ + ["lastName", "asc"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let document = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize the cbor"); + let last_name = document + .get("lastName") + .expect("we should be able to get the last name") + .as_text() + .expect("last name must be a string"); + + assert_eq!(last_name, "Randolf"); + + // A query getting all people who's first name is Chris (which is not exist) + + let query_value = json!({ + "where": [ + ["firstName", "==", "Chris"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 0); + + // A query getting a middle name + + let query_value = json!({ + "where": [ + ["middleName", "==", "Briggs"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + None, + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // A query getting all people who's first name is before Chris + + let query_value = json!({ + "where": [ + ["firstName", "<", "Chris"] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_names_before_chris = [ + "Adey".to_string(), + "Briney".to_string(), + "Cammi".to_string(), + "Celinda".to_string(), + ]; + assert_eq!(names, expected_names_before_chris); + + // A query getting all people who's first name is before Chris + + let query_value = json!({ + "where": [ + ["firstName", "StartsWith", "C"] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_names_before_chris = ["Cammi".to_string(), "Celinda".to_string()]; + assert_eq!(names, expected_names_before_chris); + + // A query getting all people who's first name is between Chris and Noellyn included + + let query_value = json!({ + "where": [ + ["firstName", ">", "Chris"], + ["firstName", "<=", "Noellyn"] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + assert_eq!(results.len(), 5); + + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_between_names = [ + "Dalia".to_string(), + "Gilligan".to_string(), + "Kevina".to_string(), + "Meta".to_string(), + "Noellyn".to_string(), + ]; + + assert_eq!(names, expected_between_names); + + // A query getting all people who's first name is between Chris and Noellyn included + // However here there will be a startAt of the ID of Kevina + + // Let's first get the ID of Kevina + let ids: HashMap> = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let name = name_value + .as_text() + .expect("the first name should be a string") + .to_string(); + (name, document.id().to_vec()) + }) + .collect(); + + let kevina_id = ids + .get("Kevina") + .expect("We should be able to get back Kevina's Id"); + let kevina_encoded_id = bs58::encode(kevina_id).into_string(); + + let query_value = json!({ + "where": [ + ["firstName", ">", "Chris"], + ["firstName", "<=", "Noellyn"] + ], + "startAt": kevina_encoded_id, //Kevina + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + assert_eq!(results.len(), 3); + + let reduced_names_after: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_reduced_names = [ + "Kevina".to_string(), + "Meta".to_string(), + "Noellyn".to_string(), + ]; + + assert_eq!(reduced_names_after, expected_reduced_names); + + // Now lets try startsAfter + + let query_value = json!({ + "where": [ + ["firstName", ">", "Chris"], + ["firstName", "<=", "Noellyn"] + ], + "startAfter": kevina_encoded_id, //Kevina + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + assert_eq!(results.len(), 2); + + let reduced_names_after: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let expected_reduced_names = ["Meta".to_string(), "Noellyn".to_string()]; + + assert_eq!(reduced_names_after, expected_reduced_names); + + // A query getting back elements having specific names + + let query_value = json!({ + "where": [ + ["firstName", "in", names] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + assert_eq!(names, expected_between_names); + + let query_value = json!({ + "where": [ + ["firstName", "in", names] + ], + "limit": 100, + "orderBy": [ + ["firstName", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .clone() + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + let ages: Vec = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let age_value = document + .get("age") + .expect("we should be able to get the age"); + let age: u64 = age_value + .to_integer() + .expect("the age should be put in an u64"); + age + }) + .collect(); + + let expected_reversed_between_names = [ + "Noellyn".to_string(), // 40 + "Meta".to_string(), // 69 + "Kevina".to_string(), // 58 + "Gilligan".to_string(), // 59 + "Dalia".to_string(), // 78 + ]; + + assert_eq!(names, expected_reversed_between_names); + + let expected_ages = [40, 69, 58, 59, 78]; + + assert_eq!(ages, expected_ages); + + // A query getting back elements having specific names and over a certain age + + let query_value = json!({ + "where": [ + ["firstName", "in", names], + ["age", ">=", 45] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"], + ["age", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + // Kevina is 55, and is excluded from this test + let expected_names_45_over = [ + "Dalia".to_string(), + "Gilligan".to_string(), + "Kevina".to_string(), + "Meta".to_string(), + ]; + + assert_eq!(names, expected_names_45_over); + + // A query getting back elements having specific names and over a certain age + + let query_value = json!({ + "where": [ + ["firstName", "in", names], + ["age", ">", 58] + ], + "limit": 100, + "orderBy": [ + ["firstName", "asc"], + ["age", "desc"] + ] + }); + let where_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + let query = DriveDocumentQuery::from_cbor( + where_cbor.as_slice(), + &contract, + person_document_type, + &drive.config, + ) + .expect("query should be built"); + let (results, _, _) = query + .execute_raw_results_no_proof(&drive, None, None, platform_version) + .expect("proof should be executed"); + let names: Vec = results + .iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let first_name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let first_name = first_name_value + .as_text() + .expect("the first name should be a string"); + String::from(first_name) + }) + .collect(); + + // Kevina is 48 so she should be now excluded, Dalia is 68, Gilligan is 49 and Meta is 59 + + let expected_names_over_48 = [ + "Dalia".to_string(), + "Gilligan".to_string(), + "Meta".to_string(), + ]; + + assert_eq!(names, expected_names_over_48); + + let ages: HashMap = results + .into_iter() + .map(|result| { + let document = + Document::from_bytes(result.as_slice(), person_document_type, platform_version) + .expect("we should be able to deserialize the cbor"); + let name_value = document + .get("firstName") + .expect("we should be able to get the first name"); + let name = name_value + .as_text() + .expect("the first name should be a string") + .to_string(); + let age_value = document + .get("age") + .expect("we should be able to get the age"); + let age: u8 = age_value.to_integer().expect("age should be an integer"); + (name, age) + }) + .collect(); + + let meta_age = ages + .get("Meta") + .expect("we should be able to get Kevina as she is 48"); + + assert_eq!(*meta_age, 69); + + // fetching by $id + let mut rng = rand::rngs::StdRng::seed_from_u64(84594); + let id_bytes = bs58::decode("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD") + .into_vec() + .expect("this should decode"); + + let owner_id_bytes = bs58::decode("BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj") + .into_vec() + .expect("this should decode"); + + let fixed_person = Person { + id: id_bytes, + owner_id: owner_id_bytes, + first_name: String::from("Wisdom"), + middle_name: String::from("Madabuchukwu"), + last_name: String::from("Ogwu"), + message: Some(String::from("Oh no")), + age: rng.gen_range(0..85), + }; + let serialized_person = serde_json::to_value(fixed_person).expect("serialized person"); + let person_cbor = cbor_serializer::serializable_value_to_cbor(&serialized_person, Some(0)) + .expect("expected to serialize to cbor"); + let document = Document::from_cbor(person_cbor.as_slice(), None, None, platform_version) + .expect("document should be properly deserialized"); + + let document_type = contract + .document_type_for_name("person") + .expect("expected to get document type"); + + let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0))); + + drive + .add_document_for_contract( + DocumentAndContractInfo { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentRefInfo((&document, storage_flags)), + owner_id: None, + }, + contract: &contract, + document_type, + }, + true, + BlockInfo::genesis(), + true, + Some(&db_transaction), + platform_version, + Some(&epoch_change_fee_version_test), + ) + .expect("document should be inserted"); + + let id_two_bytes = bs58::decode("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179") + .into_vec() + .expect("should decode"); + let owner_id_bytes = bs58::decode("Di8dtJXv3L2YnzDNUN4w5rWLPSsSAzv6hLMMQbg3eyVA") + .into_vec() + .expect("this should decode"); + let next_person = Person { + id: id_two_bytes, + owner_id: owner_id_bytes, + first_name: String::from("Wdskdfslgjfdlj"), + middle_name: String::from("Mdsfdsgsdl"), + last_name: String::from("dkfjghfdk"), + message: Some(String::from("Bad name")), + age: rng.gen_range(0..85), + }; + let serialized_person = serde_json::to_value(next_person).expect("serialized person"); + let person_cbor = cbor_serializer::serializable_value_to_cbor(&serialized_person, Some(0)) + .expect("expected to serialize to cbor"); + let document = Document::from_cbor(person_cbor.as_slice(), None, None, platform_version) + .expect("document should be properly deserialized"); + + let document_type = contract + .document_type_for_name("person") + .expect("expected to get document type"); + + let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0))); + + drive + .add_document_for_contract( + DocumentAndContractInfo { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentRefInfo((&document, storage_flags)), + owner_id: None, + }, + contract: &contract, + document_type, + }, + true, + BlockInfo::genesis(), + true, + Some(&db_transaction), + platform_version, + None, + ) + .expect("document should be inserted"); + + let query_value = json!({ + "where": [ + ["$id", "in", vec![String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let query_value = json!({ + "where": [ + ["$id", "==", "6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179"] + ] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + let query_value = json!({ + "where": [ + ["$id", "==", "6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179"] + ], + "blockTime": 300 + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // fetching by $id with order by + + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + "orderBy": [["$id", "asc"]], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 2); + + let last_person = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize the cbor"); + + assert_eq!( + last_person.id().to_vec(), + vec![ + 76, 161, 17, 201, 152, 232, 129, 48, 168, 13, 49, 10, 218, 53, 118, 136, 165, 198, 189, + 116, 116, 22, 133, 92, 104, 165, 186, 249, 94, 81, 45, 20 + ] + .as_slice() + ); + + // fetching by $id with order by desc + + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + "orderBy": [["$id", "desc"]], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 2); + + let last_person = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize the cbor"); + + assert_eq!( + last_person.id().to_vec(), + vec![ + 140, 161, 17, 201, 152, 232, 129, 48, 168, 13, 49, 10, 218, 53, 118, 136, 165, 198, + 189, 116, 116, 22, 133, 92, 104, 165, 186, 249, 94, 81, 45, 20 + ] + .as_slice() + ); + + // + // // fetching with empty where and orderBy + // + let query_value = json!({}); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 12); + + // + // // fetching with empty where and orderBy $id desc + // + let query_value = json!({ + "orderBy": [["$id", "desc"]] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 12); + + let last_person = Document::from_bytes( + results.first().unwrap().as_slice(), + person_document_type, + platform_version, + ) + .expect("we should be able to deserialize the cbor"); + + assert_eq!( + last_person.id().to_vec(), + vec![ + 249, 170, 70, 122, 181, 31, 35, 176, 175, 131, 70, 150, 250, 223, 194, 203, 175, 200, + 107, 252, 199, 227, 154, 105, 89, 57, 38, 85, 236, 192, 254, 88 + ] + .as_slice() + ); + + let message_value = last_person.get("message").unwrap(); + + let message = message_value + .as_text() + .expect("the message should be a string") + .to_string(); + + assert_eq!( + message, + String::from("“Since it’s the customer that pays our salary, our responsibility is to make the product they want, when they want it, and deliv") + ); + + // + // // fetching with empty where and orderBy $id desc with a blockTime + // + let query_value = json!({ + "orderBy": [["$id", "desc"]], + "blockTime": 300 + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect_err("not yet implemented"); + + // assert_eq!(results.len(), 12); + // + // let last_person = Document::from_bytes(results.first().unwrap().as_slice(), person_document_type, platform_version) + // .expect("we should be able to deserialize the cbor"); + // + // assert_eq!( + // last_person.id, + // vec![ + // 249, 170, 70, 122, 181, 31, 35, 176, 175, 131, 70, 150, 250, 223, 194, 203, 175, 200, + // 107, 252, 199, 227, 154, 105, 89, 57, 38, 85, 236, 192, 254, 88 + // ] + // .as_slice() + // ); + // + // let message_value = last_person.get("message").unwrap(); + // + // let message = message_value + // .as_text() + // .expect("the message should be a string") + // .to_string(); + // + // assert_eq!( + // message, + // String::from("“Since it’s the customer that pays our salary, our responsibility is to make the product they want, when they want it, and deliver quality that satisfies them.” Retired factory worker, Kiyoshi Tsutsumi (Osono et al 2008, 136)") + // ); + + // + // // fetching with ownerId in a set of values + // + let query_value = json!({ + "where": [ + ["$ownerId", "in", ["BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj", "Di8dtJXv3L2YnzDNUN4w5rWLPSsSAzv6hLMMQbg3eyVA"]] + ], + "orderBy": [["$ownerId", "desc"]] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 2); + + // + // // fetching with ownerId equal and orderBy + // + let query_value = json!({ + "where": [ + ["$ownerId", "==", "BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj"] + ], + "orderBy": [["$ownerId", "asc"]] + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 1); + + // query empty contract with nested path queries + + let dashpay_contract = json_document_to_contract( + "tests/supporting_files/contract/dashpay/dashpay-contract.json", + false, + platform_version, + ) + .expect("expected to get cbor document"); + + drive + .apply_contract( + &dashpay_contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + Some(&db_transaction), + platform_version, + ) + .expect("expected to apply contract successfully"); + + let query_value = json!({ + "where": [ + ["$ownerId", "==", "BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj"], + ["toUserId", "==", "BYR3zJgXDuz1BYAkEagwSjVqTcE1gbqEojd6RwAGuMzj"], + ], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let (results, _, _) = drive + .query_documents_cbor_from_contract( + &dashpay_contract, + dashpay_contract + .document_type_for_name("contactRequest") + .expect("should have contact document type"), + &query_cbor, + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ) + .expect("query should be executed"); + + assert_eq!(results.len(), 0); + + // using non existing document in startAt + + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + "startAt": String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF178"), + "orderBy": [["$id", "asc"]], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let result = drive.query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ); + + assert!( + matches!(result, Err(Error::Query(QuerySyntaxError::StartDocumentNotFound(message))) if message == "startAt document not found") + ); + + // using non-existing document in startAfter + + let query_value = json!({ + "where": [ + ["$id", "in", [String::from("ATxXeP5AvY4aeUFA6WRo7uaBKTBgPQCjTrgtNpCMNVRD"), String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF179")]], + ], + "startAfter": String::from("6A8SGgdmj2NtWCYoYDPDpbsYkq2MCbgi6Lx4ALLfF178"), + "orderBy": [["$id", "asc"]], + }); + + let query_cbor = cbor_serializer::serializable_value_to_cbor(&query_value, None) + .expect("expected to serialize to cbor"); + + let person_document_type = contract + .document_type_for_name("person") + .expect("contract should have a person document type"); + + let result = drive.query_documents_cbor_from_contract( + &contract, + person_document_type, + query_cbor.as_slice(), + None, + Some(&db_transaction), + Some(platform_version.protocol_version), + ); + + assert!( + matches!(result, Err(Error::Query(QuerySyntaxError::StartDocumentNotFound(message))) if message == "startAfter document not found") + ); + + // validate eventual root hash + + let root_hash = drive + .grove + .root_hash(Some(&db_transaction), &platform_version.drive.grove_version) + .unwrap() + .expect("there is always a root hash"); + assert_eq!( + root_hash.as_slice(), + vec![ + 203, 160, 200, 71, 200, 156, 249, 93, 201, 35, 171, 6, 57, 176, 159, 104, 26, 253, 141, + 193, 153, 0, 212, 9, 207, 239, 250, 51, 68, 228, 210, 164 + ] + ); +} diff --git a/packages/rs-drive/tests/supporting_files/contract/tokens/token-example-contract.json b/packages/rs-drive/tests/supporting_files/contract/tokens/token-example-contract.json new file mode 100644 index 0000000000..2a47ff22bc --- /dev/null +++ b/packages/rs-drive/tests/supporting_files/contract/tokens/token-example-contract.json @@ -0,0 +1,23 @@ +{ + "$format_version": "0", + "id": "AcYUCSvAmUwryNsQqkqqD1o3BnFuzepGtR3Mhh2swLk6", + "ownerId": "HLfavpy1B2mVHnpYYDKDVM76eWJRqvPfuuASy7cyJBXC", + "version": 1, + "tokens": { + "flurgon": { + "shouldCapitalize": true, + "pluralForm": "flurgons", + "maintainer": "GQcEb4CaXEXtPUpnJyHUt78jDij6etgEXUKyect7ZRSm", + "initialSupply": 100000000000, + "decimals": 8, + "transferable": true, + "maxSupply": 100000000000, + "roles": { + "maintainer": { + "canMint": true, + "canBurn": true + } + } + } + } +} diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 1364598fc1..e7e66db2df 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 = { version = "2.2.1" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } 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 91fd85cbae..6f74987f92 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 @@ -1,5 +1,6 @@ use versioned_feature_core::{FeatureVersion, FeatureVersionBounds}; pub mod v1; +pub mod v2; #[derive(Clone, Debug, Default)] pub struct DPPContractVersions { 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 new file mode 100644 index 0000000000..5dd797e201 --- /dev/null +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_contract_versions/v2.rs @@ -0,0 +1,54 @@ +use crate::version::dpp_versions::dpp_contract_versions::{ + DPPContractVersions, DataContractMethodVersions, DocumentTypeClassMethodVersions, + DocumentTypeIndexVersions, DocumentTypeMethodVersions, DocumentTypeSchemaVersions, + DocumentTypeVersions, RecursiveSchemaValidatorVersions, +}; +use versioned_feature_core::FeatureVersionBounds; + +pub const CONTRACT_VERSIONS_V2: DPPContractVersions = DPPContractVersions { + max_serialized_size: 65000, + contract_serialization_version: FeatureVersionBounds { + min_version: 0, + max_version: 1, + default_current_version: 1, //changed + }, + contract_structure_version: 1, //changed + created_data_contract_structure: 0, + config: 0, + methods: DataContractMethodVersions { + validate_document: 0, + validate_update: 0, + schema: 0, + }, + document_type_versions: DocumentTypeVersions { + index_versions: DocumentTypeIndexVersions { + index_levels_from_indices: 0, + }, + class_method_versions: DocumentTypeClassMethodVersions { + try_from_schema: 0, + create_document_types_from_document_schemas: 1, //changed to allow contracts with only tokens + }, + structure_version: 0, + schema: DocumentTypeSchemaVersions { + enrich_with_base_schema: 0, + find_identifier_and_binary_paths: 0, + validate_max_depth: 0, + max_depth: 256, + recursive_schema_validator_versions: RecursiveSchemaValidatorVersions { + traversal_validator: 0, + }, + validate_schema_compatibility: 0, + }, + methods: DocumentTypeMethodVersions { + create_document_from_data: 0, + create_document_with_prevalidated_properties: 0, + prefunded_voting_balance_for_document: 0, + contested_vote_poll_for_document: 0, + estimated_size: 0, + index_for_types: 0, + max_size: 0, + serialize_value_for_key: 0, + deserialize_value_for_key: 0, + }, + }, +}; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs index 3ad838e5de..8d69f6f8b6 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs @@ -1,6 +1,7 @@ use versioned_feature_core::FeatureVersionBounds; pub mod v1; +pub mod v2; #[derive(Clone, Debug, Default)] pub struct DPPStateTransitionSerializationVersions { @@ -13,7 +14,7 @@ pub struct DPPStateTransitionSerializationVersions { pub masternode_vote_state_transition: FeatureVersionBounds, pub contract_create_state_transition: FeatureVersionBounds, pub contract_update_state_transition: FeatureVersionBounds, - pub documents_batch_state_transition: FeatureVersionBounds, + pub batch_state_transition: FeatureVersionBounds, pub document_base_state_transition: FeatureVersionBounds, pub document_create_state_transition: DocumentFeatureVersionBounds, pub document_replace_state_transition: DocumentFeatureVersionBounds, diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs index 917b8405f0..944e613c26 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs @@ -50,7 +50,7 @@ pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V1: DPPStateTransitionSerializ max_version: 0, default_current_version: 0, }, - documents_batch_state_transition: FeatureVersionBounds { + batch_state_transition: FeatureVersionBounds { min_version: 0, max_version: 0, default_current_version: 0, diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs new file mode 100644 index 0000000000..1df489c45e --- /dev/null +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs @@ -0,0 +1,105 @@ +use crate::version::dpp_versions::dpp_state_transition_serialization_versions::{ + DPPStateTransitionSerializationVersions, DocumentFeatureVersionBounds, +}; +use versioned_feature_core::FeatureVersionBounds; + +pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V2: DPPStateTransitionSerializationVersions = + DPPStateTransitionSerializationVersions { + identity_public_key_in_creation: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_create_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_update_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_top_up_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_credit_withdrawal_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_credit_transfer_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + masternode_vote_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + contract_create_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + contract_update_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + batch_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 1, + default_current_version: 1, + }, + document_base_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + document_create_state_transition: DocumentFeatureVersionBounds { + bounds: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, + document_replace_state_transition: DocumentFeatureVersionBounds { + bounds: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, + document_delete_state_transition: DocumentFeatureVersionBounds { + bounds: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, + document_transfer_state_transition: DocumentFeatureVersionBounds { + bounds: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, + document_update_price_state_transition: DocumentFeatureVersionBounds { + bounds: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, + document_purchase_state_transition: DocumentFeatureVersionBounds { + bounds: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, + }; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs new file mode 100644 index 0000000000..2fa2f4f905 --- /dev/null +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/mod.rs @@ -0,0 +1,9 @@ +pub mod v1; + +use versioned_feature_core::FeatureVersion; + +#[derive(Clone, Debug, Default)] +pub struct DPPTokenVersions { + pub identity_token_info_default_structure_version: FeatureVersion, + pub identity_token_status_default_structure_version: FeatureVersion, +} diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs new file mode 100644 index 0000000000..d36fdbf9a2 --- /dev/null +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_token_versions/v1.rs @@ -0,0 +1,6 @@ +use crate::version::dpp_versions::dpp_token_versions::DPPTokenVersions; + +pub const TOKEN_VERSIONS_V1: DPPTokenVersions = DPPTokenVersions { + identity_token_info_default_structure_version: 0, + identity_token_status_default_structure_version: 0, +}; 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 ebaa11678f..c794e0ae1b 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 @@ -15,6 +15,7 @@ pub struct DPPValidationVersions { pub struct DataContractValidationVersions { pub validate: FeatureVersion, pub validate_config_update: FeatureVersion, + pub validate_token_config_update: FeatureVersion, pub validate_index_definitions: FeatureVersion, pub validate_index_naming_duplicates: FeatureVersion, pub validate_not_defined_properties: FeatureVersion, 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 e698694e62..38dd978bf0 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 @@ -13,6 +13,7 @@ pub const DPP_VALIDATION_VERSIONS_V1: DPPValidationVersions = DPPValidationVersi data_contract: DataContractValidationVersions { validate: 0, validate_config_update: 0, + validate_token_config_update: 0, validate_index_definitions: 0, validate_index_naming_duplicates: 0, validate_not_defined_properties: 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 7122390711..dcc7727e15 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 @@ -13,6 +13,7 @@ pub const DPP_VALIDATION_VERSIONS_V2: DPPValidationVersions = DPPValidationVersi data_contract: DataContractValidationVersions { validate: 0, validate_config_update: 0, + validate_token_config_update: 0, validate_index_definitions: 0, validate_index_naming_duplicates: 0, validate_not_defined_properties: 0, diff --git a/packages/rs-platform-version/src/version/dpp_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/mod.rs index e51203512c..c58be60aec 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/mod.rs @@ -9,6 +9,7 @@ pub mod dpp_state_transition_conversion_versions; pub mod dpp_state_transition_method_versions; pub mod dpp_state_transition_serialization_versions; pub mod dpp_state_transition_versions; +pub mod dpp_token_versions; pub mod dpp_validation_versions; pub mod dpp_voting_versions; @@ -23,6 +24,7 @@ use dpp_state_transition_conversion_versions::DPPStateTransitionConversionVersio use dpp_state_transition_method_versions::DPPStateTransitionMethodVersions; use dpp_state_transition_serialization_versions::DPPStateTransitionSerializationVersions; use dpp_state_transition_versions::DPPStateTransitionVersions; +use dpp_token_versions::DPPTokenVersions; use dpp_validation_versions::DPPValidationVersions; use dpp_voting_versions::DPPVotingVersions; @@ -39,6 +41,7 @@ pub struct DPPVersion { pub document_versions: DPPDocumentVersions, pub identity_versions: DPPIdentityVersions, pub voting_versions: DPPVotingVersions, + pub token_versions: DPPTokenVersions, pub asset_lock_versions: DPPAssetLockVersions, pub methods: DPPMethodVersions, pub factory_versions: DPPFactoryVersions, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs index 8d671176f4..18afbf4a15 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs @@ -5,6 +5,7 @@ pub mod v2; pub mod v3; pub mod v4; pub mod v5; +pub mod v6; #[derive(Clone, Debug, Default)] pub struct DriveAbciMethodVersions { @@ -13,6 +14,7 @@ pub struct DriveAbciMethodVersions { pub core_based_updates: DriveAbciCoreBasedUpdatesMethodVersions, pub protocol_upgrade: DriveAbciProtocolUpgradeMethodVersions, pub block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions, + pub tokens_processing: DriveAbciTokensProcessingMethodVersions, pub core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants, pub core_instant_send_lock: DriveAbciCoreInstantSendLockMethodVersions, pub fee_pool_inwards_distribution: DriveAbciFeePoolInwardsDistributionMethodVersions, @@ -76,7 +78,12 @@ pub struct DriveAbciInitializationMethodVersions { #[derive(Clone, Debug, Default)] pub struct DriveAbciBlockFeeProcessingMethodVersions { pub add_process_epoch_change_operations: FeatureVersion, - pub process_block_fees: FeatureVersion, + pub process_block_fees_and_validate_sum_trees: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveAbciTokensProcessingMethodVersions { + pub validate_token_aggregated_balance: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs index e6e1c63a40..922358607b 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs @@ -8,7 +8,8 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, - DriveAbciStateTransitionProcessingMethodVersions, DriveAbciVotingMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, }; pub const DRIVE_ABCI_METHOD_VERSIONS_V1: DriveAbciMethodVersions = DriveAbciMethodVersions { @@ -52,7 +53,10 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V1: DriveAbciMethodVersions = DriveAbciMeth }, block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { add_process_epoch_change_operations: 0, - process_block_fees: 0, + process_block_fees_and_validate_sum_trees: 0, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, }, core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { choose_quorum: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs index 1e355fa6a2..fa1db35686 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs @@ -8,7 +8,8 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, - DriveAbciStateTransitionProcessingMethodVersions, DriveAbciVotingMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, }; pub const DRIVE_ABCI_METHOD_VERSIONS_V2: DriveAbciMethodVersions = DriveAbciMethodVersions { @@ -53,7 +54,10 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V2: DriveAbciMethodVersions = DriveAbciMeth }, block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { add_process_epoch_change_operations: 0, - process_block_fees: 0, + process_block_fees_and_validate_sum_trees: 0, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, }, core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { choose_quorum: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs index 2b48e7a034..c6439e23fd 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs @@ -8,7 +8,8 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, - DriveAbciStateTransitionProcessingMethodVersions, DriveAbciVotingMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, }; pub const DRIVE_ABCI_METHOD_VERSIONS_V3: DriveAbciMethodVersions = DriveAbciMethodVersions { @@ -52,7 +53,10 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V3: DriveAbciMethodVersions = DriveAbciMeth }, block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { add_process_epoch_change_operations: 0, - process_block_fees: 0, + process_block_fees_and_validate_sum_trees: 0, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, }, core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { choose_quorum: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs index bedfb591c3..b3d961563c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs @@ -8,7 +8,8 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, - DriveAbciStateTransitionProcessingMethodVersions, DriveAbciVotingMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, }; pub const DRIVE_ABCI_METHOD_VERSIONS_V4: DriveAbciMethodVersions = DriveAbciMethodVersions { @@ -52,7 +53,10 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V4: DriveAbciMethodVersions = DriveAbciMeth }, block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { add_process_epoch_change_operations: 0, - process_block_fees: 0, + process_block_fees_and_validate_sum_trees: 0, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, }, core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { choose_quorum: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs index 8b9e7b1eae..1490bd06ed 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs @@ -8,7 +8,8 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, - DriveAbciStateTransitionProcessingMethodVersions, DriveAbciVotingMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, }; pub const DRIVE_ABCI_METHOD_VERSIONS_V5: DriveAbciMethodVersions = DriveAbciMethodVersions { @@ -52,7 +53,10 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V5: DriveAbciMethodVersions = DriveAbciMeth }, block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { add_process_epoch_change_operations: 0, - process_block_fees: 0, + process_block_fees_and_validate_sum_trees: 0, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, }, core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { choose_quorum: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs new file mode 100644 index 0000000000..8e29725ed6 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs @@ -0,0 +1,126 @@ +use crate::version::drive_abci_versions::drive_abci_method_versions::{ + DriveAbciBlockEndMethodVersions, DriveAbciBlockFeeProcessingMethodVersions, + DriveAbciBlockStartMethodVersions, DriveAbciCoreBasedUpdatesMethodVersions, + DriveAbciCoreChainLockMethodVersionsAndConstants, DriveAbciCoreInstantSendLockMethodVersions, + DriveAbciEngineMethodVersions, DriveAbciEpochMethodVersions, + DriveAbciFeePoolInwardsDistributionMethodVersions, + DriveAbciFeePoolOutwardsDistributionMethodVersions, + DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, + DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, +}; + +// Introduced in Protocol version 8 for tokens +pub const DRIVE_ABCI_METHOD_VERSIONS_V6: DriveAbciMethodVersions = DriveAbciMethodVersions { + engine: DriveAbciEngineMethodVersions { + init_chain: 0, + check_tx: 0, + run_block_proposal: 0, + finalize_block_proposal: 0, + consensus_params_update: 1, + }, + initialization: DriveAbciInitializationMethodVersions { + initial_core_height_and_time: 0, + create_genesis_state: 1, // register the additional contracts (tokens and wallet utils) + }, + core_based_updates: DriveAbciCoreBasedUpdatesMethodVersions { + update_core_info: 0, + update_masternode_list: 0, + update_quorum_info: 0, + masternode_updates: DriveAbciMasternodeIdentitiesUpdatesMethodVersions { + get_voter_identity_key: 0, + get_operator_identity_keys: 0, + get_owner_identity_withdrawal_key: 0, + get_owner_identity_owner_key: 0, + get_voter_identifier_from_masternode_list_item: 0, + get_operator_identifier_from_masternode_list_item: 0, + create_operator_identity: 0, + create_owner_identity: 1, + create_voter_identity: 0, + disable_identity_keys: 0, + update_masternode_identities: 0, + update_operator_identity: 0, + update_owner_withdrawal_address: 1, + update_voter_identity: 0, + }, + }, + protocol_upgrade: DriveAbciProtocolUpgradeMethodVersions { + check_for_desired_protocol_upgrade: 1, + upgrade_protocol_version_on_epoch_change: 0, + perform_events_on_first_block_of_protocol_change: Some(0), + protocol_version_upgrade_percentage_needed: 67, + }, + block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { + add_process_epoch_change_operations: 0, + process_block_fees_and_validate_sum_trees: 1, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, + }, + core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { + choose_quorum: 0, + verify_chain_lock: 0, + verify_chain_lock_locally: 0, + verify_chain_lock_through_core: 0, + make_sure_core_is_synced_to_chain_lock: 0, + recent_block_count_amount: 2, + }, + core_instant_send_lock: DriveAbciCoreInstantSendLockMethodVersions { + verify_recent_signature_locally: 0, + }, + fee_pool_inwards_distribution: DriveAbciFeePoolInwardsDistributionMethodVersions { + add_distribute_block_fees_into_pools_operations: 0, + add_distribute_storage_fee_to_epochs_operations: 0, + }, + fee_pool_outwards_distribution: DriveAbciFeePoolOutwardsDistributionMethodVersions { + add_distribute_fees_from_oldest_unpaid_epoch_pool_to_proposers_operations: 0, + add_epoch_pool_to_proposers_payout_operations: 0, + find_oldest_epoch_needing_payment: 0, + fetch_reward_shares_list_for_masternode: 0, + }, + withdrawals: DriveAbciIdentityCreditWithdrawalMethodVersions { + build_untied_withdrawal_transactions_from_documents: 0, + dequeue_and_build_unsigned_withdrawal_transactions: 0, + fetch_transactions_block_inclusion_status: 0, + pool_withdrawals_into_transactions_queue: 1, + update_broadcasted_withdrawal_statuses: 0, + rebroadcast_expired_withdrawal_documents: 1, + append_signatures_and_broadcast_withdrawal_transactions: 0, + cleanup_expired_locks_of_withdrawal_amounts: 0, + }, + voting: DriveAbciVotingMethodVersions { + keep_record_of_finished_contested_resource_vote_poll: 0, + clean_up_after_vote_poll_end: 0, + clean_up_after_contested_resources_vote_poll_end: 1, + check_for_ended_vote_polls: 0, + tally_votes_for_contested_document_resource_vote_poll: 0, + award_document_to_winner: 0, + delay_vote_poll: 0, + run_dao_platform_events: 0, + remove_votes_for_removed_masternodes: 0, + }, + state_transition_processing: DriveAbciStateTransitionProcessingMethodVersions { + execute_event: 0, + process_raw_state_transitions: 0, + decode_raw_state_transitions: 0, + validate_fees_of_event: 0, + }, + epoch: DriveAbciEpochMethodVersions { + gather_epoch_info: 0, + get_genesis_time: 0, + }, + block_start: DriveAbciBlockStartMethodVersions { + clear_drive_block_cache: 0, + }, + block_end: DriveAbciBlockEndMethodVersions { + update_state_cache: 0, + update_drive_cache: 0, + validator_set_update: 2, + }, + platform_state_storage: DriveAbciPlatformStateStorageMethodVersions { + fetch_platform_state: 0, + store_platform_state: 0, + }, +}; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index 8b010c9c3d..7faf75df46 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -10,10 +10,12 @@ pub struct DriveAbciQueryVersions { pub document_query: FeatureVersionBounds, pub prefunded_specialized_balances: DriveAbciQueryPrefundedSpecializedBalancesVersions, pub identity_based_queries: DriveAbciQueryIdentityVersions, + pub token_queries: DriveAbciQueryTokenVersions, pub validator_queries: DriveAbciQueryValidatorVersions, pub data_contract_based_queries: DriveAbciQueryDataContractVersions, pub voting_based_queries: DriveAbciQueryVotingVersions, pub system: DriveAbciQuerySystemVersions, + pub group_queries: DriveAbciQueryGroupVersions, } #[derive(Clone, Debug, Default)] @@ -21,6 +23,21 @@ pub struct DriveAbciQueryPrefundedSpecializedBalancesVersions { pub balance: FeatureVersionBounds, } +#[derive(Clone, Debug, Default)] +pub struct DriveAbciQueryTokenVersions { + pub identity_token_balances: FeatureVersionBounds, + pub identities_token_balances: FeatureVersionBounds, + pub identities_token_infos: FeatureVersionBounds, + pub identity_token_infos: FeatureVersionBounds, + pub token_statuses: FeatureVersionBounds, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveAbciQueryGroupVersions { + pub group_info: FeatureVersionBounds, + pub group_infos: FeatureVersionBounds, +} + #[derive(Clone, Debug, Default)] pub struct DriveAbciQueryIdentityVersions { pub identity: FeatureVersionBounds, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index b6af08405c..e4bb8e03fb 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -1,7 +1,8 @@ use crate::version::drive_abci_versions::drive_abci_query_versions::{ - DriveAbciQueryDataContractVersions, DriveAbciQueryIdentityVersions, - DriveAbciQueryPrefundedSpecializedBalancesVersions, DriveAbciQuerySystemVersions, - DriveAbciQueryValidatorVersions, DriveAbciQueryVersions, DriveAbciQueryVotingVersions, + DriveAbciQueryDataContractVersions, DriveAbciQueryGroupVersions, + DriveAbciQueryIdentityVersions, DriveAbciQueryPrefundedSpecializedBalancesVersions, + DriveAbciQuerySystemVersions, DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, + DriveAbciQueryVersions, DriveAbciQueryVotingVersions, }; use versioned_feature_core::FeatureVersionBounds; @@ -72,6 +73,33 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV default_current_version: 0, }, }, + token_queries: DriveAbciQueryTokenVersions { + identity_token_balances: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identities_token_balances: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identities_token_infos: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_token_infos: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + token_statuses: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, validator_queries: DriveAbciQueryValidatorVersions { proposed_block_counts_by_evonode_ids: FeatureVersionBounds { min_version: 0, @@ -165,4 +193,16 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV default_current_version: 0, }, }, + group_queries: DriveAbciQueryGroupVersions { + group_info: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + group_infos: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 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 71d54cdb7c..0fe429b592 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 @@ -46,7 +46,7 @@ pub struct DriveAbciStateTransitionValidationVersions { pub masternode_vote_state_transition: DriveAbciStateTransitionValidationVersion, pub contract_create_state_transition: DriveAbciStateTransitionValidationVersion, pub contract_update_state_transition: DriveAbciStateTransitionValidationVersion, - pub documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions, + pub batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions, } #[derive(Clone, Debug, Default)] @@ -98,6 +98,21 @@ pub struct DriveAbciDocumentsStateTransitionValidationVersions { pub document_transfer_transition_state_validation: FeatureVersion, pub document_purchase_transition_state_validation: FeatureVersion, pub document_update_price_transition_state_validation: FeatureVersion, + pub token_mint_transition_structure_validation: FeatureVersion, + pub token_burn_transition_structure_validation: FeatureVersion, + pub token_transfer_transition_structure_validation: FeatureVersion, + pub token_issuance_transition_state_validation: FeatureVersion, + pub token_burn_transition_state_validation: FeatureVersion, + pub token_transfer_transition_state_validation: FeatureVersion, + pub token_base_transition_structure_validation: FeatureVersion, + pub token_freeze_transition_structure_validation: FeatureVersion, + pub token_unfreeze_transition_structure_validation: FeatureVersion, + pub token_freeze_transition_state_validation: FeatureVersion, + pub token_unfreeze_transition_state_validation: FeatureVersion, + pub token_destroy_frozen_funds_transition_structure_validation: FeatureVersion, + 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, } #[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 20820165d1..11dc69053f 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 @@ -97,7 +97,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, - documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { balance_pre_check: 0, basic_structure: 0, advanced_structure: 0, @@ -129,6 +129,21 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = document_transfer_transition_state_validation: 0, document_purchase_transition_state_validation: 0, document_update_price_transition_state_validation: 0, + token_mint_transition_structure_validation: 0, + token_burn_transition_structure_validation: 0, + token_transfer_transition_structure_validation: 0, + token_issuance_transition_state_validation: 0, + token_burn_transition_state_validation: 0, + token_transfer_transition_state_validation: 0, + token_base_transition_structure_validation: 0, + token_freeze_transition_structure_validation: 0, + token_unfreeze_transition_structure_validation: 0, + token_freeze_transition_state_validation: 0, + token_unfreeze_transition_state_validation: 0, + token_destroy_frozen_funds_transition_structure_validation: 0, + token_destroy_frozen_funds_transition_state_validation: 0, + token_emergency_action_transition_structure_validation: 0, + token_emergency_action_transition_state_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 7cd1b59353..2a08f59b38 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 @@ -97,7 +97,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, - documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { balance_pre_check: 0, basic_structure: 0, advanced_structure: 0, @@ -129,6 +129,21 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = document_transfer_transition_state_validation: 0, document_purchase_transition_state_validation: 0, document_update_price_transition_state_validation: 0, + token_mint_transition_structure_validation: 0, + token_burn_transition_structure_validation: 0, + token_transfer_transition_structure_validation: 0, + token_issuance_transition_state_validation: 0, + token_burn_transition_state_validation: 0, + token_transfer_transition_state_validation: 0, + token_base_transition_structure_validation: 0, + token_freeze_transition_structure_validation: 0, + token_unfreeze_transition_structure_validation: 0, + token_freeze_transition_state_validation: 0, + token_unfreeze_transition_state_validation: 0, + token_destroy_frozen_funds_transition_structure_validation: 0, + token_destroy_frozen_funds_transition_state_validation: 0, + token_emergency_action_transition_structure_validation: 0, + token_emergency_action_transition_state_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 42f4068cdd..d706f0d838 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 @@ -97,7 +97,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, - documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { balance_pre_check: 0, basic_structure: 0, advanced_structure: 0, @@ -129,6 +129,21 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = document_transfer_transition_state_validation: 0, document_purchase_transition_state_validation: 0, document_update_price_transition_state_validation: 0, + token_mint_transition_structure_validation: 0, + token_burn_transition_structure_validation: 0, + token_transfer_transition_structure_validation: 0, + token_issuance_transition_state_validation: 0, + token_burn_transition_state_validation: 0, + token_transfer_transition_state_validation: 0, + token_base_transition_structure_validation: 0, + token_freeze_transition_structure_validation: 0, + token_unfreeze_transition_structure_validation: 0, + token_freeze_transition_state_validation: 0, + token_unfreeze_transition_state_validation: 0, + token_destroy_frozen_funds_transition_structure_validation: 0, + token_destroy_frozen_funds_transition_state_validation: 0, + token_emergency_action_transition_structure_validation: 0, + token_emergency_action_transition_state_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 8a1659106d..0faa2b63f6 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 @@ -100,7 +100,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, - documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { balance_pre_check: 0, basic_structure: 0, advanced_structure: 0, @@ -132,6 +132,21 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = document_transfer_transition_state_validation: 0, document_purchase_transition_state_validation: 0, document_update_price_transition_state_validation: 0, + token_mint_transition_structure_validation: 0, + token_burn_transition_structure_validation: 0, + token_transfer_transition_structure_validation: 0, + token_issuance_transition_state_validation: 0, + token_burn_transition_state_validation: 0, + token_transfer_transition_state_validation: 0, + token_base_transition_structure_validation: 0, + token_freeze_transition_structure_validation: 0, + token_unfreeze_transition_structure_validation: 0, + token_freeze_transition_state_validation: 0, + token_unfreeze_transition_state_validation: 0, + token_destroy_frozen_funds_transition_structure_validation: 0, + token_destroy_frozen_funds_transition_state_validation: 0, + token_emergency_action_transition_structure_validation: 0, + token_emergency_action_transition_state_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 d48857faba..b5d4d8c3aa 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 @@ -101,7 +101,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, - documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { balance_pre_check: 0, basic_structure: 0, advanced_structure: 0, @@ -133,6 +133,21 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = document_transfer_transition_state_validation: 0, document_purchase_transition_state_validation: 0, document_update_price_transition_state_validation: 0, + token_mint_transition_structure_validation: 0, + token_burn_transition_structure_validation: 0, + token_transfer_transition_structure_validation: 0, + token_issuance_transition_state_validation: 0, + token_burn_transition_state_validation: 0, + token_transfer_transition_state_validation: 0, + token_base_transition_structure_validation: 0, + token_freeze_transition_structure_validation: 0, + token_unfreeze_transition_structure_validation: 0, + token_freeze_transition_state_validation: 0, + token_unfreeze_transition_state_validation: 0, + token_destroy_frozen_funds_transition_structure_validation: 0, + token_destroy_frozen_funds_transition_state_validation: 0, + token_emergency_action_transition_structure_validation: 0, + token_emergency_action_transition_state_validation: 0, }, }, has_nonce_validation: 1, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/mod.rs index 18cf2d3a4f..a216992f69 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/mod.rs @@ -1,6 +1,7 @@ use versioned_feature_core::FeatureVersion; pub mod v1; +pub mod v2; #[derive(Clone, Debug, Default)] pub struct DriveContractMethodVersions { diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs new file mode 100644 index 0000000000..5197624ade --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_contract_method_versions/v2.rs @@ -0,0 +1,33 @@ +use crate::version::drive_versions::drive_contract_method_versions::{ + DriveContractApplyMethodVersions, DriveContractCostsMethodVersions, + DriveContractGetMethodVersions, DriveContractInsertMethodVersions, DriveContractMethodVersions, + DriveContractProveMethodVersions, DriveContractUpdateMethodVersions, +}; + +pub const DRIVE_CONTRACT_METHOD_VERSIONS_V2: DriveContractMethodVersions = + DriveContractMethodVersions { + prove: DriveContractProveMethodVersions { + prove_contract: 0, + prove_contract_history: 0, + prove_contracts: 0, + }, + apply: DriveContractApplyMethodVersions { + apply_contract: 0, + apply_contract_with_serialization: 0, + }, + insert: DriveContractInsertMethodVersions { + add_contract_to_storage: 0, + insert_contract: 1, // <--- changed to v1 (for token insertion + }, + update: DriveContractUpdateMethodVersions { update_contract: 1 }, // <--- changed to v1 (for token insertion) + costs: DriveContractCostsMethodVersions { + add_estimation_costs_for_contract_insertion: 0, + }, + get: DriveContractGetMethodVersions { + fetch_contract: 0, + fetch_contract_with_history: 0, + get_cached_contract_with_fetch_info: 0, + get_contract_with_fetch_info: 0, + get_contracts_with_fetch_info: 0, + }, + }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs new file mode 100644 index 0000000000..20ebc59466 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs @@ -0,0 +1,38 @@ +use grovedb_version::version::FeatureVersion; + +pub mod v1; + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupMethodVersions { + pub fetch: DriveGroupFetchMethodVersions, + pub prove: DriveGroupProveMethodVersions, + pub insert: DriveGroupInsertMethodVersions, + pub cost_estimation: DriveGroupCostEstimationMethodVersions, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupFetchMethodVersions { + pub fetch_action_id_signers_power: FeatureVersion, + pub fetch_action_id_info: FeatureVersion, + pub fetch_action_id_info_keep_serialized: FeatureVersion, + pub fetch_action_id_has_signer: FeatureVersion, + pub fetch_group_info: FeatureVersion, + pub fetch_group_infos: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupProveMethodVersions { + pub prove_group_info: FeatureVersion, + pub prove_group_infos: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupInsertMethodVersions { + pub add_new_groups: FeatureVersion, + pub add_group_action: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveGroupCostEstimationMethodVersions { + pub for_add_group_action: 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 new file mode 100644 index 0000000000..365678957b --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/v1.rs @@ -0,0 +1,26 @@ +use crate::version::drive_versions::drive_group_method_versions::{ + DriveGroupCostEstimationMethodVersions, DriveGroupFetchMethodVersions, + DriveGroupInsertMethodVersions, DriveGroupMethodVersions, DriveGroupProveMethodVersions, +}; + +pub const DRIVE_GROUP_METHOD_VERSIONS_V1: DriveGroupMethodVersions = DriveGroupMethodVersions { + fetch: DriveGroupFetchMethodVersions { + fetch_action_id_signers_power: 0, + fetch_action_id_info: 0, + fetch_action_id_info_keep_serialized: 0, + fetch_action_id_has_signer: 0, + fetch_group_info: 0, + fetch_group_infos: 0, + }, + prove: DriveGroupProveMethodVersions { + prove_group_info: 0, + prove_group_infos: 0, + }, + insert: DriveGroupInsertMethodVersions { + add_new_groups: 0, + add_group_action: 0, + }, + cost_estimation: DriveGroupCostEstimationMethodVersions { + for_add_group_action: 0, + }, +}; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs index c61b52f250..71d7fc8b00 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs @@ -33,6 +33,10 @@ pub struct DriveGroveBasicMethodVersions { pub grove_get_proved_path_query_with_conditional: FeatureVersion, pub grove_get_sum_tree_total_value: FeatureVersion, pub grove_has_raw: FeatureVersion, + pub grove_get_raw_item: FeatureVersion, + pub grove_get_optional_sum_tree_total_value: FeatureVersion, + pub grove_get_raw_optional_item: FeatureVersion, + pub grove_get_big_sum_tree_total_value: FeatureVersion, } #[derive(Clone, Debug, Default)] @@ -40,6 +44,7 @@ pub struct DriveGroveBatchMethodVersions { pub batch_insert_empty_tree: FeatureVersion, pub batch_insert_empty_tree_if_not_exists: FeatureVersion, pub batch_insert_empty_tree_if_not_exists_check_existing_operations: FeatureVersion, + pub batch_insert_sum_item_if_not_exists: FeatureVersion, pub batch_insert_sum_item_or_add_to_if_already_exists: FeatureVersion, pub batch_insert: FeatureVersion, pub batch_insert_if_not_exists: FeatureVersion, @@ -51,6 +56,7 @@ pub struct DriveGroveBatchMethodVersions { pub batch_remove_raw: FeatureVersion, pub batch_delete_up_tree_while_empty: FeatureVersion, pub batch_refresh_reference: FeatureVersion, + pub batch_insert_empty_sum_tree: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs index 6dc9b44503..0fa2d7d09c 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs @@ -26,11 +26,16 @@ pub const DRIVE_GROVE_METHOD_VERSIONS_V1: DriveGroveMethodVersions = DriveGroveM grove_get_proved_path_query_with_conditional: 0, grove_get_sum_tree_total_value: 0, grove_has_raw: 0, + grove_get_raw_item: 0, + grove_get_optional_sum_tree_total_value: 0, + grove_get_raw_optional_item: 0, + grove_get_big_sum_tree_total_value: 0, }, batch: DriveGroveBatchMethodVersions { batch_insert_empty_tree: 0, batch_insert_empty_tree_if_not_exists: 0, batch_insert_empty_tree_if_not_exists_check_existing_operations: 0, + batch_insert_sum_item_if_not_exists: 0, batch_insert_sum_item_or_add_to_if_already_exists: 0, batch_insert: 0, batch_insert_if_not_exists: 0, @@ -42,6 +47,7 @@ pub const DRIVE_GROVE_METHOD_VERSIONS_V1: DriveGroveMethodVersions = DriveGroveM batch_remove_raw: 0, batch_delete_up_tree_while_empty: 0, batch_refresh_reference: 0, + batch_insert_empty_sum_tree: 0, }, apply: DriveGroveApplyMethodVersions { grove_apply_operation: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/mod.rs index c44788e4c3..958724c7a8 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/mod.rs @@ -58,6 +58,8 @@ pub struct DriveIdentityContractInfoMethodVersions { pub struct DriveIdentityCostEstimationMethodVersions { pub for_authentication_keys_security_level_in_key_reference_tree: FeatureVersion, pub for_balances: FeatureVersion, + pub for_token_balances: FeatureVersion, + pub for_token_total_supply: FeatureVersion, pub for_contract_info: FeatureVersion, pub for_contract_info_group: FeatureVersion, pub for_contract_info_group_keys: FeatureVersion, @@ -67,6 +69,7 @@ pub struct DriveIdentityCostEstimationMethodVersions { pub for_purpose_in_key_reference_tree: FeatureVersion, pub for_root_key_reference_tree: FeatureVersion, pub for_update_revision: FeatureVersion, + pub for_token_identity_infos: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/v1.rs index 098f38ab7c..385078e380 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_identity_method_versions/v1.rs @@ -119,6 +119,8 @@ pub const DRIVE_IDENTITY_METHOD_VERSIONS_V1: DriveIdentityMethodVersions = cost_estimation: DriveIdentityCostEstimationMethodVersions { for_authentication_keys_security_level_in_key_reference_tree: 0, for_balances: 0, + for_token_balances: 0, + for_token_total_supply: 0, for_contract_info: 0, for_contract_info_group: 0, for_contract_info_group_keys: 0, @@ -128,6 +130,7 @@ pub const DRIVE_IDENTITY_METHOD_VERSIONS_V1: DriveIdentityMethodVersions = for_purpose_in_key_reference_tree: 0, for_root_key_reference_tree: 0, for_update_revision: 0, + for_token_identity_infos: 0, }, withdrawals: DriveIdentityWithdrawalMethodVersions { document: DriveIdentityWithdrawalDocumentMethodVersions { 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 c482548908..58fa89dddd 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 @@ -20,6 +20,9 @@ pub struct DriveStateTransitionActionConvertToHighLevelOperationsMethodVersions pub document_replace_transition: FeatureVersion, pub document_transfer_transition: FeatureVersion, pub document_update_price_transition: FeatureVersion, + pub token_burn_transition: FeatureVersion, + pub token_mint_transition: FeatureVersion, + pub token_transfer_transition: FeatureVersion, pub documents_batch_transition: FeatureVersion, pub identity_create_transition: FeatureVersion, pub identity_credit_transfer_transition: FeatureVersion, @@ -30,6 +33,10 @@ pub struct DriveStateTransitionActionConvertToHighLevelOperationsMethodVersions pub bump_identity_data_contract_nonce: FeatureVersion, pub bump_identity_nonce: FeatureVersion, pub partially_use_asset_lock: FeatureVersion, + pub token_freeze_transition: FeatureVersion, + pub token_unfreeze_transition: FeatureVersion, + pub token_emergency_action_transition: FeatureVersion, + pub token_destroy_frozen_funds_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 45e732c99c..772b880711 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 @@ -22,6 +22,9 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1: DriveStateTransitionMethodV document_replace_transition: 0, document_transfer_transition: 0, document_update_price_transition: 0, + token_burn_transition: 0, + token_mint_transition: 0, + token_transfer_transition: 0, documents_batch_transition: 0, identity_create_transition: 0, identity_credit_transfer_transition: 0, @@ -32,5 +35,9 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1: DriveStateTransitionMethodV bump_identity_data_contract_nonce: 0, bump_identity_nonce: 0, partially_use_asset_lock: 0, + token_freeze_transition: 0, + token_unfreeze_transition: 0, + token_emergency_action_transition: 0, + token_destroy_frozen_funds_transition: 0, }, }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs new file mode 100644 index 0000000000..e10ff81316 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs @@ -0,0 +1,50 @@ +use versioned_feature_core::FeatureVersion; + +pub mod v1; + +#[derive(Clone, Debug, Default)] +pub struct DriveTokenMethodVersions { + pub fetch: DriveTokenFetchMethodVersions, + pub prove: DriveTokenProveMethodVersions, + pub update: DriveTokenUpdateMethodVersions, + pub calculate_total_tokens_balance: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveTokenFetchMethodVersions { + pub identity_token_balance: FeatureVersion, + pub identity_token_balances: FeatureVersion, + pub identities_token_balances: FeatureVersion, + pub identity_token_info: FeatureVersion, + pub identity_token_infos: FeatureVersion, + pub identities_token_infos: FeatureVersion, + pub token_statuses: FeatureVersion, + pub token_status: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveTokenProveMethodVersions { + pub identity_token_balance: FeatureVersion, + pub identity_token_balances: FeatureVersion, + pub identities_token_balances: FeatureVersion, + pub identity_token_info: FeatureVersion, + pub identity_token_infos: FeatureVersion, + pub identities_token_infos: FeatureVersion, + pub token_statuses: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveTokenUpdateMethodVersions { + pub create_token_trees: FeatureVersion, + pub burn: FeatureVersion, + pub mint: FeatureVersion, + pub transfer: FeatureVersion, + pub add_to_token_total_supply: FeatureVersion, + pub remove_from_token_total_supply: FeatureVersion, + pub remove_from_identity_token_balance: FeatureVersion, + pub add_to_identity_token_balance: FeatureVersion, + pub add_transaction_history_operations: FeatureVersion, + pub freeze: FeatureVersion, + pub unfreeze: FeatureVersion, + pub apply_status: FeatureVersion, +} diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs new file mode 100644 index 0000000000..9b8f9d83ad --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs @@ -0,0 +1,41 @@ +use crate::version::drive_versions::drive_token_method_versions::{ + DriveTokenFetchMethodVersions, DriveTokenMethodVersions, DriveTokenProveMethodVersions, + DriveTokenUpdateMethodVersions, +}; + +pub const DRIVE_TOKEN_METHOD_VERSIONS_V1: DriveTokenMethodVersions = DriveTokenMethodVersions { + fetch: DriveTokenFetchMethodVersions { + identity_token_balance: 0, + identity_token_balances: 0, + identities_token_balances: 0, + identity_token_info: 0, + identity_token_infos: 0, + identities_token_infos: 0, + token_statuses: 0, + token_status: 0, + }, + prove: DriveTokenProveMethodVersions { + identity_token_balance: 0, + identity_token_balances: 0, + identities_token_balances: 0, + identity_token_info: 0, + identity_token_infos: 0, + identities_token_infos: 0, + token_statuses: 0, + }, + update: DriveTokenUpdateMethodVersions { + create_token_trees: 0, + burn: 0, + mint: 0, + transfer: 0, + add_to_token_total_supply: 0, + remove_from_token_total_supply: 0, + remove_from_identity_token_balance: 0, + add_to_identity_token_balance: 0, + add_transaction_history_operations: 0, + freeze: 0, + unfreeze: 0, + apply_status: 0, + }, + calculate_total_tokens_balance: 0, +}; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index 39d4255136..e23fd54276 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -7,6 +7,7 @@ pub struct DriveVerifyMethodVersions { pub contract: DriveVerifyContractMethodVersions, pub document: DriveVerifyDocumentMethodVersions, pub identity: DriveVerifyIdentityMethodVersions, + pub token: DriveVerifyTokenMethodVersions, pub single_document: DriveVerifySingleDocumentMethodVersions, pub system: DriveVerifySystemMethodVersions, pub voting: DriveVerifyVoteMethodVersions, @@ -42,6 +43,13 @@ pub struct DriveVerifyIdentityMethodVersions { pub verify_identity_revision_for_identity_id: FeatureVersion, } +#[derive(Clone, Debug, Default)] +pub struct DriveVerifyTokenMethodVersions { + pub verify_token_balances_for_identity_ids: FeatureVersion, + pub verify_token_balances_for_identity_id: FeatureVersion, + pub verify_token_infos_for_identity_ids: FeatureVersion, +} + #[derive(Clone, Debug, Default)] pub struct DriveVerifyVoteMethodVersions { pub verify_masternode_vote: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index 4c40371f83..56813f3b0b 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -2,7 +2,7 @@ use crate::version::drive_versions::drive_verify_method_versions::{ DriveVerifyContractMethodVersions, DriveVerifyDocumentMethodVersions, DriveVerifyIdentityMethodVersions, DriveVerifyMethodVersions, DriveVerifySingleDocumentMethodVersions, DriveVerifyStateTransitionMethodVersions, - DriveVerifySystemMethodVersions, DriveVerifyVoteMethodVersions, + DriveVerifySystemMethodVersions, DriveVerifyTokenMethodVersions, DriveVerifyVoteMethodVersions, }; pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVerifyMethodVersions { @@ -29,6 +29,11 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri verify_identities_contract_keys: 0, verify_identity_revision_for_identity_id: 0, }, + token: DriveVerifyTokenMethodVersions { + verify_token_balances_for_identity_ids: 0, + verify_token_balances_for_identity_id: 0, + verify_token_infos_for_identity_ids: 0, + }, single_document: DriveVerifySingleDocumentMethodVersions { verify_proof: 0, verify_proof_keep_serialized: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/mod.rs index 262ac9407a..dd5c1b1a15 100644 --- a/packages/rs-platform-version/src/version/drive_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/mod.rs @@ -2,10 +2,12 @@ use crate::version::FeatureVersion; use drive_contract_method_versions::DriveContractMethodVersions; use drive_credit_pool_method_versions::DriveCreditPoolMethodVersions; use drive_document_method_versions::DriveDocumentMethodVersions; +use drive_group_method_versions::DriveGroupMethodVersions; use drive_grove_method_versions::DriveGroveMethodVersions; use drive_identity_method_versions::DriveIdentityMethodVersions; use drive_state_transition_method_versions::DriveStateTransitionMethodVersions; use drive_structure_version::DriveStructureVersion; +use drive_token_method_versions::DriveTokenMethodVersions; use drive_verify_method_versions::DriveVerifyMethodVersions; use drive_vote_method_versions::DriveVoteMethodVersions; use grovedb_version::version::GroveVersion; @@ -13,15 +15,18 @@ use grovedb_version::version::GroveVersion; pub mod drive_contract_method_versions; pub mod drive_credit_pool_method_versions; pub mod drive_document_method_versions; +pub mod drive_group_method_versions; pub mod drive_grove_method_versions; pub mod drive_identity_method_versions; pub mod drive_state_transition_method_versions; pub mod drive_structure_version; +pub mod drive_token_method_versions; pub mod drive_verify_method_versions; pub mod drive_vote_method_versions; pub mod v1; pub mod v2; pub mod v3; +pub mod v4; #[derive(Clone, Debug, Default)] pub struct DriveVersion { @@ -46,6 +51,7 @@ pub struct DriveMethodVersions { pub asset_lock: DriveAssetLockMethodVersions, pub verify: DriveVerifyMethodVersions, pub identity: DriveIdentityMethodVersions, + pub token: DriveTokenMethodVersions, pub platform_system: DrivePlatformSystemMethodVersions, pub operations: DriveOperationsMethodVersion, pub batch_operations: DriveBatchOperationsMethodVersion, @@ -53,6 +59,7 @@ pub struct DriveMethodVersions { pub prove: DriveProveMethodVersions, pub state_transitions: DriveStateTransitionMethodVersions, pub platform_state: DrivePlatformStateMethodVersions, + pub group: DriveGroupMethodVersions, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/v1.rs index 3ba9dc974f..1daae27b5b 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v1.rs @@ -1,10 +1,12 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_structure_version::v1::DRIVE_STRUCTURE_V1; +use crate::version::drive_versions::drive_token_method_versions::v1::DRIVE_TOKEN_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_verify_method_versions::v1::DRIVE_VERIFY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_vote_method_versions::v1::DRIVE_VOTE_METHOD_VERSIONS_V1; use crate::version::drive_versions::{ @@ -61,6 +63,7 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { }, verify: DRIVE_VERIFY_METHOD_VERSIONS_V1, identity: DRIVE_IDENTITY_METHOD_VERSIONS_V1, + token: DRIVE_TOKEN_METHOD_VERSIONS_V1, platform_system: DrivePlatformSystemMethodVersions { estimation_costs: DriveSystemEstimationCostsMethodVersions { for_total_system_credits_update: 0, @@ -95,6 +98,7 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { estimated_cost_for_prefunded_specialized_balance_update: 0, empty_prefunded_specialized_balance: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/v2.rs index 0881f6ca55..b76e79c7f9 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v2.rs @@ -1,10 +1,12 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_structure_version::v1::DRIVE_STRUCTURE_V1; +use crate::version::drive_versions::drive_token_method_versions::v1::DRIVE_TOKEN_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_verify_method_versions::v1::DRIVE_VERIFY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_METHOD_VERSIONS_V2; use crate::version::drive_versions::{ @@ -61,6 +63,7 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { }, verify: DRIVE_VERIFY_METHOD_VERSIONS_V1, identity: DRIVE_IDENTITY_METHOD_VERSIONS_V1, + token: DRIVE_TOKEN_METHOD_VERSIONS_V1, platform_system: DrivePlatformSystemMethodVersions { estimation_costs: DriveSystemEstimationCostsMethodVersions { for_total_system_credits_update: 0, @@ -95,6 +98,7 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { estimated_cost_for_prefunded_specialized_balance_update: 0, empty_prefunded_specialized_balance: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v3.rs b/packages/rs-platform-version/src/version/drive_versions/v3.rs index 2f3efb3729..4af61e282e 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v3.rs @@ -1,10 +1,12 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_structure_version::v1::DRIVE_STRUCTURE_V1; +use crate::version::drive_versions::drive_token_method_versions::v1::DRIVE_TOKEN_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_verify_method_versions::v1::DRIVE_VERIFY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_METHOD_VERSIONS_V2; use crate::version::drive_versions::{ @@ -61,6 +63,7 @@ pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { }, verify: DRIVE_VERIFY_METHOD_VERSIONS_V1, identity: DRIVE_IDENTITY_METHOD_VERSIONS_V1, + token: DRIVE_TOKEN_METHOD_VERSIONS_V1, platform_system: DrivePlatformSystemMethodVersions { estimation_costs: DriveSystemEstimationCostsMethodVersions { for_total_system_credits_update: 0, @@ -95,6 +98,7 @@ pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { estimated_cost_for_prefunded_specialized_balance_update: 0, empty_prefunded_specialized_balance: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v4.rs b/packages/rs-platform-version/src/version/drive_versions/v4.rs new file mode 100644 index 0000000000..34af21d7d2 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/v4.rs @@ -0,0 +1,105 @@ +use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CONTRACT_METHOD_VERSIONS_V2; +use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_structure_version::v1::DRIVE_STRUCTURE_V1; +use crate::version::drive_versions::drive_token_method_versions::v1::DRIVE_TOKEN_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_verify_method_versions::v1::DRIVE_VERIFY_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_METHOD_VERSIONS_V2; +use crate::version::drive_versions::{ + DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, + DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, + DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, + DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, + DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, + DriveProveMethodVersions, DriveSystemEstimationCostsMethodVersions, DriveVersion, +}; +use grovedb_version::version::v2::GROVE_V2; + +pub const DRIVE_VERSION_V4: DriveVersion = DriveVersion { + structure: DRIVE_STRUCTURE_V1, + methods: DriveMethodVersions { + initialization: DriveInitializationMethodVersions { + create_initial_state_structure: 1, // changed here to 1 to add token sum trees + }, + credit_pools: CREDIT_POOL_METHOD_VERSIONS_V1, + protocol_upgrade: DriveProtocolUpgradeVersions { + clear_version_information: 0, + fetch_versions_with_counter: 0, + fetch_proved_versions_with_counter: 0, + fetch_validator_version_votes: 0, + fetch_proved_validator_version_votes: 0, + remove_validators_proposed_app_versions: 0, + update_validator_proposed_app_version: 0, + }, + prove: DriveProveMethodVersions { + prove_elements: 0, + prove_multiple_state_transition_results: 0, + }, + balances: DriveBalancesMethodVersions { + add_to_system_credits: 0, + add_to_system_credits_operations: 0, + remove_from_system_credits: 0, + remove_from_system_credits_operations: 0, + calculate_total_credits_balance: 0, + }, + document: DRIVE_DOCUMENT_METHOD_VERSIONS_V1, + vote: DRIVE_VOTE_METHOD_VERSIONS_V2, + contract: DRIVE_CONTRACT_METHOD_VERSIONS_V2, // changed in v4 + fees: DriveFeesMethodVersions { calculate_fee: 0 }, + estimated_costs: DriveEstimatedCostsMethodVersions { + add_estimation_costs_for_levels_up_to_contract: 0, + add_estimation_costs_for_levels_up_to_contract_document_type_excluded: 0, + add_estimation_costs_for_contested_document_tree_levels_up_to_contract: 0, + add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded: 0, + }, + asset_lock: DriveAssetLockMethodVersions { + add_asset_lock_outpoint: 0, + add_estimation_costs_for_adding_asset_lock: 0, + fetch_asset_lock_outpoint_info: 0, + }, + verify: DRIVE_VERIFY_METHOD_VERSIONS_V1, + identity: DRIVE_IDENTITY_METHOD_VERSIONS_V1, + token: DRIVE_TOKEN_METHOD_VERSIONS_V1, + platform_system: DrivePlatformSystemMethodVersions { + estimation_costs: DriveSystemEstimationCostsMethodVersions { + for_total_system_credits_update: 0, + }, + }, + operations: DriveOperationsMethodVersion { + rollback_transaction: 0, + drop_cache: 0, + commit_transaction: 0, + apply_partial_batch_low_level_drive_operations: 0, + apply_partial_batch_grovedb_operations: 0, + apply_batch_low_level_drive_operations: 0, + apply_batch_grovedb_operations: 0, + }, + state_transitions: DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1, + batch_operations: DriveBatchOperationsMethodVersion { + convert_drive_operations_to_grove_operations: 0, + apply_drive_operations: 0, + }, + platform_state: DrivePlatformStateMethodVersions { + fetch_platform_state_bytes: 0, + store_platform_state_bytes: 0, + }, + fetch: DriveFetchMethodVersions { fetch_elements: 0 }, + prefunded_specialized_balances: DrivePrefundedSpecializedMethodVersions { + fetch_single: 0, + prove_single: 0, + add_prefunded_specialized_balance: 0, + add_prefunded_specialized_balance_operations: 1, + deduct_from_prefunded_specialized_balance: 1, + deduct_from_prefunded_specialized_balance_operations: 0, + estimated_cost_for_prefunded_specialized_balance_update: 0, + empty_prefunded_specialized_balance: 0, + }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, + }, + grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, + grove_version: GROVE_V2, //changed in V4 +}; diff --git a/packages/rs-platform-version/src/version/fee/processing/mod.rs b/packages/rs-platform-version/src/version/fee/processing/mod.rs index a4f33696c0..715e060c4a 100644 --- a/packages/rs-platform-version/src/version/fee/processing/mod.rs +++ b/packages/rs-platform-version/src/version/fee/processing/mod.rs @@ -9,6 +9,7 @@ pub struct FeeProcessingVersion { pub fetch_identity_revision_processing_cost: u64, pub fetch_identity_balance_and_revision_processing_cost: u64, pub fetch_identity_cost_per_look_up_key_by_id: u64, + pub fetch_identity_token_balance_processing_cost: u64, pub fetch_prefunded_specialized_balance_processing_cost: u64, pub fetch_single_identity_key_processing_cost: u64, pub validate_key_structure: u64, @@ -39,6 +40,9 @@ impl From for FeeProcessingVersi .fetch_identity_balance_and_revision_processing_cost, fetch_identity_cost_per_look_up_key_by_id: old .fetch_identity_cost_per_look_up_key_by_id, + fetch_identity_token_balance_processing_cost: FEE_VERSION1 + .processing + .fetch_identity_token_balance_processing_cost, fetch_prefunded_specialized_balance_processing_cost: old .fetch_prefunded_specialized_balance_processing_cost, fetch_single_identity_key_processing_cost: old diff --git a/packages/rs-platform-version/src/version/fee/processing/v1.rs b/packages/rs-platform-version/src/version/fee/processing/v1.rs index b6ba5ca998..fae3ec4939 100644 --- a/packages/rs-platform-version/src/version/fee/processing/v1.rs +++ b/packages/rs-platform-version/src/version/fee/processing/v1.rs @@ -5,6 +5,7 @@ pub const FEE_PROCESSING_VERSION1: FeeProcessingVersion = FeeProcessingVersion { fetch_identity_revision_processing_cost: 9000, fetch_identity_balance_and_revision_processing_cost: 15000, fetch_identity_cost_per_look_up_key_by_id: 9000, + fetch_identity_token_balance_processing_cost: 10000, fetch_prefunded_specialized_balance_processing_cost: 10000, fetch_single_identity_key_processing_cost: 10000, perform_network_threshold_signing: 100000000, // 1mDash (2.5 cents at 25$/Dash) 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 e1371648ff..26c64a4d7c 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -10,14 +10,16 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v1:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v1::STATE_TRANSITION_VERSIONS_V1; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v1::DRIVE_ABCI_METHOD_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_query_versions::{ - DriveAbciQueryDataContractVersions, DriveAbciQueryIdentityVersions, - DriveAbciQueryPrefundedSpecializedBalancesVersions, DriveAbciQuerySystemVersions, - DriveAbciQueryValidatorVersions, DriveAbciQueryVersions, DriveAbciQueryVotingVersions, + DriveAbciQueryDataContractVersions, DriveAbciQueryGroupVersions, + DriveAbciQueryIdentityVersions, DriveAbciQueryPrefundedSpecializedBalancesVersions, + DriveAbciQuerySystemVersions, DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, + DriveAbciQueryVersions, DriveAbciQueryVotingVersions, }; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v1::DRIVE_ABCI_VALIDATION_VERSIONS_V1; @@ -26,10 +28,12 @@ use crate::version::drive_abci_versions::DriveAbciVersion; use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CONTRACT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_state_transition_method_versions::v1::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_structure_version::v1::DRIVE_STRUCTURE_V1; +use crate::version::drive_versions::drive_token_method_versions::v1::DRIVE_TOKEN_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_verify_method_versions::v1::DRIVE_VERIFY_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_vote_method_versions::v1::DRIVE_VOTE_METHOD_VERSIONS_V1; use crate::version::drive_versions::{ @@ -95,6 +99,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { }, verify: DRIVE_VERIFY_METHOD_VERSIONS_V1, identity: DRIVE_IDENTITY_METHOD_VERSIONS_V1, + token: DRIVE_TOKEN_METHOD_VERSIONS_V1, platform_system: DrivePlatformSystemMethodVersions { estimation_costs: DriveSystemEstimationCostsMethodVersions { for_total_system_credits_update: 0, @@ -129,6 +134,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { estimated_cost_for_prefunded_specialized_balance_update: 0, empty_prefunded_specialized_balance: 0, }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, @@ -205,6 +211,33 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { default_current_version: 0, }, }, + token_queries: DriveAbciQueryTokenVersions { + identity_token_balances: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identities_token_balances: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identities_token_infos: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + identity_token_infos: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + token_statuses: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, validator_queries: DriveAbciQueryValidatorVersions { proposed_block_counts_by_evonode_ids: FeatureVersionBounds { min_version: 0, @@ -298,6 +331,18 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { default_current_version: 0, }, }, + group_queries: DriveAbciQueryGroupVersions { + group_info: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + group_infos: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, }, }, dpp: DPPVersion { @@ -311,6 +356,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/mocks/v3_test.rs b/packages/rs-platform-version/src/version/mocks/v3_test.rs index 4c54dfbfef..3a8964266d 100644 --- a/packages/rs-platform-version/src/version/mocks/v3_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v3_test.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v1::STATE_TRANSITION_VERSIONS_V1; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -23,7 +24,8 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, - DriveAbciStateTransitionProcessingMethodVersions, DriveAbciVotingMethodVersions, + DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, + DriveAbciVotingMethodVersions, }; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; @@ -85,7 +87,10 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { }, block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions { add_process_epoch_change_operations: 0, - process_block_fees: 0, + process_block_fees_and_validate_sum_trees: 0, + }, + tokens_processing: DriveAbciTokensProcessingMethodVersions { + validate_token_aggregated_balance: 0, }, core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants { choose_quorum: 0, @@ -167,6 +172,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/mod.rs b/packages/rs-platform-version/src/version/mod.rs index 430317100c..5718d916d0 100644 --- a/packages/rs-platform-version/src/version/mod.rs +++ b/packages/rs-platform-version/src/version/mod.rs @@ -1,5 +1,5 @@ mod protocol_version; -use crate::version::v8::PROTOCOL_VERSION_8; +use crate::version::v9::PROTOCOL_VERSION_9; pub use protocol_version::*; mod consensus_versions; @@ -20,8 +20,9 @@ pub mod v5; pub mod v6; pub mod v7; pub mod v8; +pub mod v9; pub type ProtocolVersion = u32; -pub const LATEST_VERSION: ProtocolVersion = PROTOCOL_VERSION_8; +pub const LATEST_VERSION: ProtocolVersion = PROTOCOL_VERSION_9; pub const INITIAL_PROTOCOL_VERSION: ProtocolVersion = 1; diff --git a/packages/rs-platform-version/src/version/protocol_version.rs b/packages/rs-platform-version/src/version/protocol_version.rs index 520ceef97a..d25532718f 100644 --- a/packages/rs-platform-version/src/version/protocol_version.rs +++ b/packages/rs-platform-version/src/version/protocol_version.rs @@ -23,6 +23,8 @@ use crate::version::v5::PLATFORM_V5; use crate::version::v6::PLATFORM_V6; use crate::version::v7::PLATFORM_V7; use crate::version::v8::PLATFORM_V8; +use crate::version::v9::PLATFORM_V9; + use crate::version::ProtocolVersion; pub use versioned_feature_core::*; @@ -47,6 +49,7 @@ pub const PLATFORM_VERSIONS: &[PlatformVersion] = &[ PLATFORM_V6, PLATFORM_V7, PLATFORM_V8, + PLATFORM_V9, ]; #[cfg(feature = "mock-versions")] @@ -55,7 +58,7 @@ pub static PLATFORM_TEST_VERSIONS: OnceLock> = OnceLock::ne #[cfg(feature = "mock-versions")] const DEFAULT_PLATFORM_TEST_VERSIONS: &[PlatformVersion] = &[TEST_PLATFORM_V2, TEST_PLATFORM_V3]; -pub const LATEST_PLATFORM_VERSION: &PlatformVersion = &PLATFORM_V8; +pub const LATEST_PLATFORM_VERSION: &PlatformVersion = &PLATFORM_V9; pub const DESIRED_PLATFORM_VERSION: &PlatformVersion = LATEST_PLATFORM_VERSION; diff --git a/packages/rs-platform-version/src/version/v1.rs b/packages/rs-platform-version/src/version/v1.rs index f7803b32c5..5f32d406fa 100644 --- a/packages/rs-platform-version/src/version/v1.rs +++ b/packages/rs-platform-version/src/version/v1.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v1:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v1::STATE_TRANSITION_VERSIONS_V1; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v1::DPP_VALIDATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_voting_versions::v1::VOTING_VERSION_V1; use crate::version::dpp_versions::DPPVersion; @@ -49,6 +50,7 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V1, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v2.rs b/packages/rs-platform-version/src/version/v2.rs index 6e1ed40094..f97bee4139 100644 --- a/packages/rs-platform-version/src/version/v2.rs +++ b/packages/rs-platform-version/src/version/v2.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v1:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v1::STATE_TRANSITION_VERSIONS_V1; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v1::VOTING_VERSION_V1; use crate::version::dpp_versions::DPPVersion; @@ -49,6 +50,7 @@ pub const PLATFORM_V2: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V1, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v3.rs b/packages/rs-platform-version/src/version/v3.rs index f3856bc1e6..c92b8ab225 100644 --- a/packages/rs-platform-version/src/version/v3.rs +++ b/packages/rs-platform-version/src/version/v3.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -56,6 +57,7 @@ pub const PLATFORM_V3: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v4.rs b/packages/rs-platform-version/src/version/v4.rs index d0b5894374..a6086b01ef 100644 --- a/packages/rs-platform-version/src/version/v4.rs +++ b/packages/rs-platform-version/src/version/v4.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -51,6 +52,7 @@ pub const PLATFORM_V4: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v5.rs b/packages/rs-platform-version/src/version/v5.rs index 988531b3d0..1679fff28a 100644 --- a/packages/rs-platform-version/src/version/v5.rs +++ b/packages/rs-platform-version/src/version/v5.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -51,6 +52,7 @@ pub const PLATFORM_V5: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v6.rs b/packages/rs-platform-version/src/version/v6.rs index b282d1b752..3ae597d99f 100644 --- a/packages/rs-platform-version/src/version/v6.rs +++ b/packages/rs-platform-version/src/version/v6.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -50,6 +51,7 @@ pub const PLATFORM_V6: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v7.rs b/packages/rs-platform-version/src/version/v7.rs index 0857a94ae9..1c1824b320 100644 --- a/packages/rs-platform-version/src/version/v7.rs +++ b/packages/rs-platform-version/src/version/v7.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -50,6 +51,7 @@ pub const PLATFORM_V7: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, methods: DPP_METHOD_VERSIONS_V1, factory_versions: DPP_FACTORY_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v8.rs b/packages/rs-platform-version/src/version/v8.rs index 7e86606215..9b6e7eff5a 100644 --- a/packages/rs-platform-version/src/version/v8.rs +++ b/packages/rs-platform-version/src/version/v8.rs @@ -10,6 +10,7 @@ use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2:: use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v1::STATE_TRANSITION_SERIALIZATION_VERSIONS_V1; use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; @@ -54,6 +55,7 @@ pub const PLATFORM_V8: PlatformVersion = PlatformVersion { document_versions: DOCUMENT_VERSIONS_V1, identity_versions: IDENTITY_VERSIONS_V1, voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, // We changed `daily_withdrawal_limit` to v1 to increase daily withdrawal limit // to 2000 Dash. diff --git a/packages/rs-platform-version/src/version/v9.rs b/packages/rs-platform-version/src/version/v9.rs new file mode 100644 index 0000000000..e8713306d2 --- /dev/null +++ b/packages/rs-platform-version/src/version/v9.rs @@ -0,0 +1,66 @@ +use crate::version::consensus_versions::ConsensusVersions; +use crate::version::dpp_versions::dpp_asset_lock_versions::v1::DPP_ASSET_LOCK_VERSIONS_V1; +use crate::version::dpp_versions::dpp_contract_versions::v2::CONTRACT_VERSIONS_V2; +use crate::version::dpp_versions::dpp_costs_versions::v1::DPP_COSTS_VERSIONS_V1; +use crate::version::dpp_versions::dpp_document_versions::v1::DOCUMENT_VERSIONS_V1; +use crate::version::dpp_versions::dpp_factory_versions::v1::DPP_FACTORY_VERSIONS_V1; +use crate::version::dpp_versions::dpp_identity_versions::v1::IDENTITY_VERSIONS_V1; +use crate::version::dpp_versions::dpp_method_versions::v1::DPP_METHOD_VERSIONS_V1; +use crate::version::dpp_versions::dpp_state_transition_conversion_versions::v2::STATE_TRANSITION_CONVERSION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_state_transition_method_versions::v1::STATE_TRANSITION_METHOD_VERSIONS_V1; +use crate::version::dpp_versions::dpp_state_transition_serialization_versions::v2::STATE_TRANSITION_SERIALIZATION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_state_transition_versions::v2::STATE_TRANSITION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_token_versions::v1::TOKEN_VERSIONS_V1; +use crate::version::dpp_versions::dpp_validation_versions::v2::DPP_VALIDATION_VERSIONS_V2; +use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; +use crate::version::dpp_versions::DPPVersion; +use crate::version::drive_abci_versions::drive_abci_method_versions::v6::DRIVE_ABCI_METHOD_VERSIONS_V6; +use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_validation_versions::v4::DRIVE_ABCI_VALIDATION_VERSIONS_V4; +use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; +use crate::version::drive_abci_versions::DriveAbciVersion; +use crate::version::drive_versions::v4::DRIVE_VERSION_V4; +use crate::version::fee::v1::FEE_VERSION1; +use crate::version::protocol_version::PlatformVersion; +use crate::version::system_data_contract_versions::v1::SYSTEM_DATA_CONTRACT_VERSIONS_V1; +use crate::version::system_limits::v1::SYSTEM_LIMITS_V1; +use crate::version::ProtocolVersion; + +pub const PROTOCOL_VERSION_9: ProtocolVersion = 9; + +/// This version adds token support. +//todo: make changes +pub const PLATFORM_V9: PlatformVersion = PlatformVersion { + protocol_version: PROTOCOL_VERSION_9, + drive: DRIVE_VERSION_V4, // changed (for data contract insert) + drive_abci: DriveAbciVersion { + structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V1, + methods: DRIVE_ABCI_METHOD_VERSIONS_V6, // changed because of the genesis state + validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V4, + withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, + query: DRIVE_ABCI_QUERY_VERSIONS_V1, + }, + dpp: DPPVersion { + costs: DPP_COSTS_VERSIONS_V1, + validation: DPP_VALIDATION_VERSIONS_V2, + state_transition_serialization_versions: STATE_TRANSITION_SERIALIZATION_VERSIONS_V2, // changed + state_transition_conversion_versions: STATE_TRANSITION_CONVERSION_VERSIONS_V2, + state_transition_method_versions: STATE_TRANSITION_METHOD_VERSIONS_V1, + state_transitions: STATE_TRANSITION_VERSIONS_V2, + contract_versions: CONTRACT_VERSIONS_V2, // changed + document_versions: DOCUMENT_VERSIONS_V1, + identity_versions: IDENTITY_VERSIONS_V1, + voting_versions: VOTING_VERSION_V2, + token_versions: TOKEN_VERSIONS_V1, + asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, + methods: DPP_METHOD_VERSIONS_V1, + factory_versions: DPP_FACTORY_VERSIONS_V1, + }, + system_data_contracts: SYSTEM_DATA_CONTRACT_VERSIONS_V1, + fee_version: FEE_VERSION1, + system_limits: SYSTEM_LIMITS_V1, + consensus: ConsensusVersions { + tenderdash_consensus_version: 1, + }, +}; diff --git a/packages/rs-sdk/src/platform/transition/purchase_document.rs b/packages/rs-sdk/src/platform/transition/purchase_document.rs index 530c1c6b83..8423bd66d0 100644 --- a/packages/rs-sdk/src/platform/transition/purchase_document.rs +++ b/packages/rs-sdk/src/platform/transition/purchase_document.rs @@ -9,8 +9,8 @@ use dpp::fee::Credits; use dpp::identity::signer::Signer; use dpp::identity::IdentityPublicKey; use dpp::prelude::Identifier; -use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; #[async_trait::async_trait] @@ -65,7 +65,7 @@ impl PurchaseDocument for Document { let settings = settings.unwrap_or_default(); - let transition = DocumentsBatchTransition::new_document_purchase_transition_from_document( + let transition = BatchTransition::new_document_purchase_transition_from_document( self.clone(), document_type.as_ref(), purchaser_id, diff --git a/packages/rs-sdk/src/platform/transition/put_document.rs b/packages/rs-sdk/src/platform/transition/put_document.rs index 3ef5c5c864..a18b9143ea 100644 --- a/packages/rs-sdk/src/platform/transition/put_document.rs +++ b/packages/rs-sdk/src/platform/transition/put_document.rs @@ -7,8 +7,8 @@ use dpp::data_contract::document_type::DocumentType; use dpp::document::{Document, DocumentV0Getters}; use dpp::identity::signer::Signer; use dpp::identity::IdentityPublicKey; -use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; #[async_trait::async_trait] @@ -60,7 +60,7 @@ impl PutDocument for Document { let settings = settings.unwrap_or_default(); - let transition = DocumentsBatchTransition::new_document_creation_transition_from_document( + let transition = BatchTransition::new_document_creation_transition_from_document( self.clone(), document_type.as_ref(), document_state_transition_entropy, diff --git a/packages/rs-sdk/src/platform/transition/transfer_document.rs b/packages/rs-sdk/src/platform/transition/transfer_document.rs index 2106141ae3..bd4a87e2dd 100644 --- a/packages/rs-sdk/src/platform/transition/transfer_document.rs +++ b/packages/rs-sdk/src/platform/transition/transfer_document.rs @@ -8,8 +8,8 @@ use dpp::data_contract::document_type::DocumentType; use dpp::document::{Document, DocumentV0Getters}; use dpp::identity::signer::Signer; use dpp::identity::IdentityPublicKey; -use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; use rs_dapi_client::{DapiRequest, IntoInner}; @@ -62,7 +62,7 @@ impl TransferDocument for Document { let settings = settings.unwrap_or_default(); - let transition = DocumentsBatchTransition::new_document_transfer_transition_from_document( + let transition = BatchTransition::new_document_transfer_transition_from_document( self.clone(), document_type.as_ref(), recipient_id, diff --git a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs index 99a5642bf9..e0bb06e0ef 100644 --- a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs +++ b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs @@ -9,8 +9,9 @@ use dpp::document::{Document, DocumentV0Getters}; use dpp::fee::Credits; use dpp::identity::signer::Signer; use dpp::identity::IdentityPublicKey; -use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::state_transition::batch_transition::BatchTransition; +use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::state_transition::StateTransition; #[async_trait::async_trait] @@ -62,20 +63,19 @@ impl UpdatePriceOfDocument for Document { let settings = settings.unwrap_or_default(); - let transition = - DocumentsBatchTransition::new_document_update_price_transition_from_document( - self.clone(), - document_type.as_ref(), - price, - &identity_public_key, - new_identity_contract_nonce, - settings.user_fee_increase.unwrap_or_default(), - signer, - sdk.version(), - None, - None, - None, - )?; + let transition = BatchTransition::new_document_update_price_transition_from_document( + self.clone(), + document_type.as_ref(), + price, + &identity_public_key, + new_identity_contract_nonce, + settings.user_fee_increase.unwrap_or_default(), + signer, + sdk.version(), + None, + None, + None, + )?; // response is empty for a broadcast, result comes from the stream wait for state transition result transition.broadcast(sdk, Some(settings)).await?; diff --git a/packages/rs-sdk/src/platform/transition/waitable.rs b/packages/rs-sdk/src/platform/transition/waitable.rs index a63acb0949..c17436776d 100644 --- a/packages/rs-sdk/src/platform/transition/waitable.rs +++ b/packages/rs-sdk/src/platform/transition/waitable.rs @@ -43,7 +43,7 @@ impl Waitable for Document { state_transition: StateTransition, settings: Option, ) -> Result { - let doc_id = if let StateTransition::DocumentsBatch(transition) = &state_transition { + let doc_id = if let StateTransition::Batch(transition) = &state_transition { let ids = transition.modified_data_ids(); if ids.len() != 1 { return Err(Error::Protocol( diff --git a/packages/search-contract/.eslintrc b/packages/search-contract/.eslintrc new file mode 100644 index 0000000000..cb6c7636b6 --- /dev/null +++ b/packages/search-contract/.eslintrc @@ -0,0 +1,18 @@ +{ + "extends": "airbnb-base", + "rules": { + "no-plusplus": 0, + "eol-last": [ + "error", + "always" + ], + "class-methods-use-this": "off", + "curly": [ + "error", + "all" + ] + }, + "globals": { + "BigInt": true + } +} diff --git a/packages/search-contract/.mocharc.yml b/packages/search-contract/.mocharc.yml new file mode 100644 index 0000000000..164b941c1b --- /dev/null +++ b/packages/search-contract/.mocharc.yml @@ -0,0 +1,2 @@ +require: test/bootstrap.js +recursive: true diff --git a/packages/search-contract/Cargo.toml b/packages/search-contract/Cargo.toml new file mode 100644 index 0000000000..3625f97a47 --- /dev/null +++ b/packages/search-contract/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "token-history-contract" +description = "Token history data contract schema and tools" +version = "1.6.2" +edition = "2021" +rust-version.workspace = true +license = "MIT" + +[dependencies] +thiserror = "1.0.64" +platform-version = { path = "../rs-platform-version" } +serde_json = { version = "1.0" } +platform-value = { path = "../rs-platform-value" } diff --git a/packages/search-contract/LICENSE b/packages/search-contract/LICENSE new file mode 100644 index 0000000000..3be9583375 --- /dev/null +++ b/packages/search-contract/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2019 Dash Core Group, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/search-contract/README.md b/packages/search-contract/README.md new file mode 100644 index 0000000000..6f6caf4d9d --- /dev/null +++ b/packages/search-contract/README.md @@ -0,0 +1,26 @@ +# Search Contract + +[![Build Status](https://github.com/dashpay/platform/actions/workflows/release.yml/badge.svg)](https://github.com/dashpay/platform/actions/workflows/release.yml) +[![NPM version](https://img.shields.io/npm/v/@dashevo/wallet-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/wallet-contract) + +JSON Contracts for Searching Data Contracts + +## Table of Contents + +- [Install](#install) +- [Contributing](#contributing) +- [License](#license) + +## Install + +```sh +npm install @dashevo/search-contract +``` + +## Contributing + +Feel free to dive in! [Open an issue](https://github.com/dashpay/platform/issues/new/choose) or submit PRs. + +## License + +[MIT](LICENSE) © Dash Core Group, Inc. diff --git a/packages/search-contract/lib/systemIds.js b/packages/search-contract/lib/systemIds.js new file mode 100644 index 0000000000..7335d3d163 --- /dev/null +++ b/packages/search-contract/lib/systemIds.js @@ -0,0 +1,4 @@ +module.exports = { + ownerId: '11111111111111111111111111111111', + contractId: '8v8CoKCDdBcQu1Y7GDNJjR7a5vkMmgpXycJURkaUhfU9', +}; diff --git a/packages/search-contract/package.json b/packages/search-contract/package.json new file mode 100644 index 0000000000..82782f0d62 --- /dev/null +++ b/packages/search-contract/package.json @@ -0,0 +1,29 @@ +{ + "name": "@dashevo/search-contract", + "version": "1.6.2", + "description": "A contract that allows searching for contracts", + "scripts": { + "lint": "eslint .", + "test": "yarn run test:unit", + "test:unit": "mocha 'test/unit/**/*.spec.js'" + }, + "contributors": [ + { + "name": "Samuel Westrich", + "email": "sam@dash.org", + "url": "https://github.com/quantumexplorer" + } + ], + "license": "MIT", + "devDependencies": { + "@dashevo/wasm-dpp": "workspace:*", + "chai": "^4.3.10", + "dirty-chai": "^2.0.1", + "eslint": "^8.53.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.29.0", + "mocha": "^10.2.0", + "sinon": "^17.0.1", + "sinon-chai": "^3.7.0" + } +} diff --git a/packages/search-contract/schema/v1/search-contract-documents.json b/packages/search-contract/schema/v1/search-contract-documents.json new file mode 100644 index 0000000000..f146ecb3e6 --- /dev/null +++ b/packages/search-contract/schema/v1/search-contract-documents.json @@ -0,0 +1,62 @@ +{ + "contract": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "referenceType": "contract", + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byKeyword", + "properties": [ + { + "keyword": "asc" + } + ] + } + ], + "properties": { + "keyword": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "position": 0 + } + }, + "required": [ + "$contractId", + "keyword" + ], + "additionalProperties": false + }, + "token": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "referenceType": "token", + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byKeyword", + "properties": [ + { + "keyword": "asc" + } + ] + } + ], + "properties": { + "keyword": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "position": 0 + } + }, + "required": [ + "$tokenId", + "keyword" + ], + "additionalProperties": false + } +} diff --git a/packages/search-contract/src/error.rs b/packages/search-contract/src/error.rs new file mode 100644 index 0000000000..d01bbcc91c --- /dev/null +++ b/packages/search-contract/src/error.rs @@ -0,0 +1,17 @@ +use platform_version::version::FeatureVersion; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// Platform expected some specific versions + #[error("platform unknown version on {method}, received: {received}")] + UnknownVersionMismatch { + /// method + method: String, + /// the allowed versions for this method + known_versions: Vec, + /// requested core height + received: FeatureVersion, + }, + #[error("schema deserialize error: {0}")] + InvalidSchemaJson(#[from] serde_json::Error), +} diff --git a/packages/search-contract/src/lib.rs b/packages/search-contract/src/lib.rs new file mode 100644 index 0000000000..f7767ea6c2 --- /dev/null +++ b/packages/search-contract/src/lib.rs @@ -0,0 +1,37 @@ +mod error; +pub mod v1; + +pub use crate::error::Error; +use platform_value::{Identifier, IdentifierBytes32}; +use platform_version::version::PlatformVersion; +use serde_json::Value; + +pub const ID_BYTES: [u8; 32] = [ + 92, 20, 14, 101, 92, 2, 101, 187, 194, 168, 8, 113, 109, 225, 132, 121, 133, 19, 89, 24, 173, + 81, 205, 253, 11, 118, 102, 75, 169, 91, 163, 124, +]; + +pub const OWNER_ID_BYTES: [u8; 32] = [0; 32]; + +pub const ID: Identifier = Identifier(IdentifierBytes32(ID_BYTES)); +pub const OWNER_ID: Identifier = Identifier(IdentifierBytes32(OWNER_ID_BYTES)); +pub fn load_definitions(platform_version: &PlatformVersion) -> Result, Error> { + match platform_version.system_data_contracts.withdrawals { + 1 => Ok(None), + version => Err(Error::UnknownVersionMismatch { + method: "search_contract::load_definitions".to_string(), + known_versions: vec![1], + received: version, + }), + } +} +pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result { + match platform_version.system_data_contracts.withdrawals { + 1 => v1::load_documents_schemas(), + version => Err(Error::UnknownVersionMismatch { + method: "search_contract::load_documents_schemas".to_string(), + known_versions: vec![1], + received: version, + }), + } +} diff --git a/packages/search-contract/src/v1/mod.rs b/packages/search-contract/src/v1/mod.rs new file mode 100644 index 0000000000..e5d6a06771 --- /dev/null +++ b/packages/search-contract/src/v1/mod.rs @@ -0,0 +1,27 @@ +use crate::Error; +use serde_json::Value; + +pub mod document_types { + pub mod contract { + pub const NAME: &str = "contract"; + + pub mod properties { + pub const KEY_INDEX: &str = "byKeyword"; + } + } + + pub mod token { + pub const NAME: &str = "token"; + + pub mod properties { + pub const KEY_INDEX: &str = "byKeyword"; + } + } +} + +pub fn load_documents_schemas() -> Result { + serde_json::from_str(include_str!( + "../../schema/v1/search-contract-documents.json" + )) + .map_err(Error::InvalidSchemaJson) +} diff --git a/packages/search-contract/test/.eslintrc b/packages/search-contract/test/.eslintrc new file mode 100644 index 0000000000..720ced7385 --- /dev/null +++ b/packages/search-contract/test/.eslintrc @@ -0,0 +1,12 @@ +{ + "env": { + "node": true, + "mocha": true + }, + "rules": { + "import/no-extraneous-dependencies": "off" + }, + "globals": { + "expect": true + } +} diff --git a/packages/search-contract/test/bootstrap.js b/packages/search-contract/test/bootstrap.js new file mode 100644 index 0000000000..7af04f464d --- /dev/null +++ b/packages/search-contract/test/bootstrap.js @@ -0,0 +1,30 @@ +const sinon = require('sinon'); +const sinonChai = require('sinon-chai'); + +const { expect, use } = require('chai'); +const dirtyChai = require('dirty-chai'); + +const { + default: loadWasmDpp, +} = require('@dashevo/wasm-dpp'); + +use(dirtyChai); +use(sinonChai); + +exports.mochaHooks = { + beforeAll: loadWasmDpp, + + beforeEach() { + if (!this.sinon) { + this.sinon = sinon.createSandbox(); + } else { + this.sinon.restore(); + } + }, + + afterEach() { + this.sinon.restore(); + }, +}; + +global.expect = expect; diff --git a/packages/search-contract/test/unit/searchContract.spec.js b/packages/search-contract/test/unit/searchContract.spec.js new file mode 100644 index 0000000000..2fd94a879b --- /dev/null +++ b/packages/search-contract/test/unit/searchContract.spec.js @@ -0,0 +1,187 @@ +const crypto = require('crypto'); + +const { + DashPlatformProtocol, + JsonSchemaError, +} = require('@dashevo/wasm-dpp'); +const generateRandomIdentifier = require('@dashevo/wasm-dpp/lib/test/utils/generateRandomIdentifierAsync'); + +const { expect } = require('chai'); +const walletContractDocumentsSchema = require('../../schema/v1/search-contract-documents.json'); + +const expectJsonSchemaError = (validationResult, errorCount = 1) => { + const errors = validationResult.getErrors(); + expect(errors) + .to + .have + .length(errorCount); + + const error = validationResult.getErrors()[0]; + expect(error) + .to + .be + .instanceof(JsonSchemaError); + + return error; +}; + +describe('Search Contract', () => { + let dpp; + let dataContract; + let identityId; + + beforeEach(async () => { + dpp = new DashPlatformProtocol( + { generate: () => crypto.randomBytes(32) }, + ); + + identityId = await generateRandomIdentifier(); + + dataContract = dpp.dataContract.create(identityId, BigInt(1), walletContractDocumentsSchema); + }); + + it('should have a valid contract definition', async () => { + expect(() => dpp.dataContract.create(identityId, BigInt(1), walletContractDocumentsSchema)) + .to + .not + .throw(); + }); + + describe('documents', () => { + describe('txMetadata', () => { + let rawTxMetadataDocument; + + beforeEach(() => { + rawTxMetadataDocument = { + keyIndex: 0, + encryptionKeyIndex: 100, + encryptedMetadata: crypto.randomBytes(64), + }; + }); + + describe('keyIndex', () => { + it('should be defined', async () => { + delete rawTxMetadataDocument.keyIndex; + + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword) + .to + .equal('required'); + expect(error.params.missingProperty) + .to + .equal('keyIndex'); + }); + + it('should be a non-negative integer', async () => { + rawTxMetadataDocument.keyIndex = -1; + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + describe('encryptionKeyIndex', () => { + it('should be defined', async () => { + delete rawTxMetadataDocument.encryptionKeyIndex; + + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword) + .to + .equal('required'); + expect(error.params.missingProperty) + .to + .equal('encryptionKeyIndex'); + }); + + it('should be a non-negative integer', async () => { + rawTxMetadataDocument.encryptionKeyIndex = -1; + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + describe('encryptedMetadata', () => { + it('should be defined', async () => { + delete rawTxMetadataDocument.encryptedMetadata; + + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword) + .to + .equal('required'); + expect(error.params.missingProperty) + .to + .equal('encryptedMetadata'); + }); + + it('should be not shorter than 32 bytes', async () => { + rawTxMetadataDocument.encryptedMetadata = crypto.randomBytes(31); + + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword) + .to + .equal('minItems'); + expect(error.instancePath) + .to + .equal('/encryptedMetadata'); + }); + + it('should be not longer than 4096 bytes', async () => { + rawTxMetadataDocument.encryptedMetadata = crypto.randomBytes(4097); + + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword) + .to + .equal('maxItems'); + expect(error.instancePath) + .to + .equal('/encryptedMetadata'); + }); + }); + + it('should not have additional properties', async () => { + rawTxMetadataDocument.someOtherProperty = 42; + + const document = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + + expect(error.keyword) + .to + .equal('additionalProperties'); + expect(error.params.additionalProperties) + .to + .deep + .equal(['someOtherProperty']); + }); + + it('should be valid', async () => { + const txMetadata = dpp.document.create(dataContract, identityId, 'txMetadata', rawTxMetadataDocument); + + const result = await txMetadata.validate(dpp.protocolVersion); + + expect(result.isValid()) + .to + .be + .true(); + }); + }); + }); +}); diff --git a/packages/strategy-tests/src/lib.rs b/packages/strategy-tests/src/lib.rs index efdb702a48..6d5d3e5161 100644 --- a/packages/strategy-tests/src/lib.rs +++ b/packages/strategy-tests/src/lib.rs @@ -37,34 +37,38 @@ use dpp::state_transition::StateTransition; use dpp::version::PlatformVersion; use drive::drive::identity::key::fetch::{IdentityKeysRequest, KeyRequestType}; +use bincode::{Decode, Encode}; use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters}; +use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; +use dpp::data_contract::document_type::DocumentType; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::identity::accessors::IdentityGettersV0; +use dpp::platform_value::{BinaryData, Bytes32, Value}; +use dpp::state_transition::batch_transition::batched_transition::document_delete_transition::DocumentDeleteTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_replace_transition::DocumentReplaceTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::document_transfer_transition::DocumentTransferTransitionV0; +use dpp::state_transition::batch_transition::batched_transition::{ + DocumentDeleteTransition, DocumentReplaceTransition, DocumentTransferTransition, +}; +use dpp::state_transition::batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; +use dpp::state_transition::batch_transition::document_create_transition::{ + DocumentCreateTransition, DocumentCreateTransitionV0, +}; +use dpp::state_transition::batch_transition::{BatchTransition, BatchTransitionV0}; +use dpp::state_transition::data_contract_create_transition::methods::v0::DataContractCreateTransitionMethodsV0; use dpp::state_transition::data_contract_update_transition::methods::DataContractUpdateTransitionMethodsV0; +use dpp::ProtocolError::{PlatformDeserializationError, PlatformSerializationError}; +use dpp::{dash_to_duffs, ProtocolError}; use operations::{DataContractUpdateAction, DataContractUpdateOp}; use platform_version::TryFromPlatformVersioned; use rand::prelude::StdRng; use rand::seq::{IteratorRandom, SliceRandom}; use rand::Rng; -use transitions::create_identity_credit_transfer_transition; +use simple_signer::signer::SimpleSigner; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::ops::RangeInclusive; -use bincode::{Decode, Encode}; -use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; -use dpp::identifier::Identifier; -use dpp::data_contract::document_type::DocumentType; -use dpp::fee::Credits; -use dpp::identity::accessors::IdentityGettersV0; -use dpp::platform_value::{BinaryData, Bytes32, Value}; -use dpp::{dash_to_duffs, ProtocolError}; -use dpp::ProtocolError::{PlatformDeserializationError, PlatformSerializationError}; -use dpp::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; -use dpp::state_transition::documents_batch_transition::document_create_transition::{DocumentCreateTransition, DocumentCreateTransitionV0}; -use dpp::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; -use dpp::state_transition::documents_batch_transition::document_transition::document_replace_transition::DocumentReplaceTransitionV0; -use dpp::state_transition::documents_batch_transition::{DocumentsBatchTransition, DocumentsBatchTransitionV0}; -use dpp::state_transition::documents_batch_transition::document_transition::{DocumentDeleteTransition, DocumentReplaceTransition, DocumentTransferTransition}; -use dpp::state_transition::data_contract_create_transition::methods::v0::DataContractCreateTransitionMethodsV0; -use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::DocumentTransferTransitionV0; -use simple_signer::signer::SimpleSigner; +use transitions::create_identity_credit_transfer_transition; pub mod frequency; pub mod operations; @@ -720,8 +724,8 @@ impl Strategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { + let document_batch_transition: BatchTransition = + BatchTransitionV0 { owner_id: identity.id(), transitions: vec![document_create_transition.into()], user_fee_increase: 0, @@ -846,8 +850,8 @@ impl Strategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { + let document_batch_transition: BatchTransition = + BatchTransitionV0 { owner_id: identity.id(), transitions: vec![document_create_transition.into()], user_fee_increase: 0, @@ -936,15 +940,14 @@ impl Strategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id: identity.id(), - transitions: vec![document_delete_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 1, - signature: BinaryData::default(), - } - .into(); + let document_batch_transition: BatchTransition = BatchTransitionV0 { + owner_id: identity.id(), + transitions: vec![document_delete_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 1, + signature: BinaryData::default(), + } + .into(); let mut document_batch_transition: StateTransition = document_batch_transition.into(); @@ -1034,15 +1037,14 @@ impl Strategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id: identity.id, - transitions: vec![document_replace_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 1, - signature: BinaryData::default(), - } - .into(); + let document_batch_transition: BatchTransition = BatchTransitionV0 { + owner_id: identity.id, + transitions: vec![document_replace_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 1, + signature: BinaryData::default(), + } + .into(); let mut document_batch_transition: StateTransition = document_batch_transition.into(); @@ -1138,15 +1140,14 @@ impl Strategy { } .into(); - let document_batch_transition: DocumentsBatchTransition = - DocumentsBatchTransitionV0 { - owner_id: identity.id, - transitions: vec![document_transfer_transition.into()], - user_fee_increase: 0, - signature_public_key_id: 1, - signature: BinaryData::default(), - } - .into(); + let document_batch_transition: BatchTransition = BatchTransitionV0 { + owner_id: identity.id, + transitions: vec![document_transfer_transition.into()], + user_fee_increase: 0, + signature_public_key_id: 1, + signature: BinaryData::default(), + } + .into(); let mut document_batch_transition: StateTransition = document_batch_transition.into(); @@ -1919,28 +1920,22 @@ mod tests { let mut simple_signer = SimpleSigner::default(); - let (identity1, keys) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity1, keys) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys); - let (identity2, keys) = - Identity::random_identity_with_main_keys_with_private_key::>( - 2, - &mut rng, - platform_version, - ) - .unwrap(); + let (mut identity2, keys) = Identity::random_identity_with_main_keys_with_private_key::< + Vec<_>, + >(2, &mut rng, platform_version) + .unwrap(); simple_signer.add_keys(keys); let start_identities = create_state_transitions_for_identities( - vec![identity1, identity2], + vec![&mut identity1, &mut identity2], &(dash_to_duffs!(1)..=dash_to_duffs!(1)), &mut simple_signer, &mut rng, diff --git a/packages/strategy-tests/src/operations.rs b/packages/strategy-tests/src/operations.rs index d35fc9f503..4dcebb9f62 100644 --- a/packages/strategy-tests/src/operations.rs +++ b/packages/strategy-tests/src/operations.rs @@ -8,7 +8,7 @@ use dpp::data_contract::document_type::random_document::{ use dpp::data_contract::document_type::v0::random_document_type::RandomDocumentTypeParameters; use dpp::data_contract::document_type::DocumentType; use dpp::data_contract::serialized_version::DataContractInSerializationFormat; -use dpp::data_contract::{DataContract as Contract, DataContract}; +use dpp::data_contract::{DataContract as Contract, DataContract, TokenContractPosition}; use dpp::fee::Credits; use dpp::identifier::Identifier; use dpp::identity::IdentityPublicKey; @@ -17,6 +17,7 @@ use dpp::serialization::{ PlatformDeserializableWithPotentialValidationFromVersionedStructure, PlatformSerializableWithPlatformVersion, }; +use dpp::tokens::token_event::TokenEvent; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use dpp::ProtocolError; use dpp::ProtocolError::{PlatformDeserializationError, PlatformSerializationError}; @@ -29,6 +30,106 @@ use rand::prelude::StdRng; use std::collections::BTreeMap; use std::ops::{Range, RangeInclusive}; +#[derive(Clone, Debug, PartialEq)] +pub struct TokenOp { + pub contract: Contract, + pub token_id: Identifier, + pub token_pos: TokenContractPosition, + pub use_identity_with_id: Option, + pub action: TokenEvent, +} + +#[derive(Clone, Debug, Encode, Decode)] +pub struct TokenOpInSerializationFormat { + pub contract: DataContractInSerializationFormat, + pub token_id: Identifier, + pub token_pos: TokenContractPosition, + pub use_identity_with_id: Option, + pub action: TokenEvent, +} + +impl PlatformSerializableWithPlatformVersion for TokenOp { + type Error = ProtocolError; + + fn serialize_to_bytes_with_platform_version( + &self, + platform_version: &PlatformVersion, + ) -> Result, ProtocolError> { + self.clone() + .serialize_consume_to_bytes_with_platform_version(platform_version) + } + + fn serialize_consume_to_bytes_with_platform_version( + self, + platform_version: &PlatformVersion, + ) -> Result, ProtocolError> { + let TokenOp { + contract, + token_id, + token_pos, + use_identity_with_id, + action, + } = self; + let data_contract_serialization_format: DataContractInSerializationFormat = + contract.try_into_platform_versioned(platform_version)?; + + let document_op = TokenOpInSerializationFormat { + contract: data_contract_serialization_format, + token_id, + token_pos, + use_identity_with_id, + action, + }; + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + bincode::encode_to_vec(document_op, config).map_err(|e| { + PlatformSerializationError(format!("unable to serialize DocumentOp: {}", e)) + }) + } +} + +impl PlatformDeserializableWithPotentialValidationFromVersionedStructure for TokenOp { + fn versioned_deserialize( + data: &[u8], + full_validation: bool, + platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized, + { + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + let token_op_in_serialization_format: TokenOpInSerializationFormat = + bincode::borrow_decode_from_slice(data, config) + .map_err(|e| { + PlatformDeserializationError(format!("unable to deserialize DocumentOp: {}", e)) + })? + .0; + let TokenOpInSerializationFormat { + contract, + token_id, + token_pos, + use_identity_with_id, + action, + } = token_op_in_serialization_format; + let data_contract = DataContract::try_from_platform_versioned( + contract, + full_validation, + &mut vec![], + platform_version, + )?; + Ok(TokenOp { + contract: data_contract, + token_id, + token_pos, + use_identity_with_id, + action, + }) + } +} + #[derive(Clone, Debug, PartialEq, Encode, Decode)] pub enum DocumentAction { DocumentActionInsertRandom(DocumentFieldFillType, DocumentFieldFillSize), @@ -514,6 +615,7 @@ pub enum OperationType { ContractUpdate(DataContractUpdateOp), IdentityTransfer(Option), ResourceVote(ResourceVoteOp), + Token(TokenOp), } #[derive(Clone, Debug, Encode, Decode)] @@ -526,6 +628,7 @@ enum OperationTypeInSerializationFormat { ContractUpdate(Vec), IdentityTransfer(Option), ResourceVote(ResourceVoteOpSerializable), + Token(Vec), } impl PlatformSerializableWithPlatformVersion for OperationType { @@ -578,6 +681,11 @@ impl PlatformSerializableWithPlatformVersion for OperationType { resource_vote_op.try_into_platform_versioned(platform_version)?; OperationTypeInSerializationFormat::ResourceVote(vote_op_in_serialization_format) } + OperationType::Token(token_op) => { + let token_op_in_serialization_format = + token_op.serialize_consume_to_bytes_with_platform_version(platform_version)?; + OperationTypeInSerializationFormat::Token(token_op_in_serialization_format) + } }; let config = bincode::config::standard() .with_big_endian() @@ -642,6 +750,14 @@ impl PlatformDeserializableWithPotentialValidationFromVersionedStructure for Ope let vote_op = resource_vote_op.try_into_platform_versioned(platform_version)?; OperationType::ResourceVote(vote_op) } + OperationTypeInSerializationFormat::Token(serialized_token_op) => { + let token_op = TokenOp::versioned_deserialize( + serialized_token_op.as_slice(), + full_validation, + platform_version, + )?; + OperationType::Token(token_op) + } }) } } diff --git a/packages/strategy-tests/src/transitions.rs b/packages/strategy-tests/src/transitions.rs index c77b51e290..d3607d179a 100644 --- a/packages/strategy-tests/src/transitions.rs +++ b/packages/strategy-tests/src/transitions.rs @@ -1018,16 +1018,19 @@ pub fn create_identities_state_transitions( /// - When unable to generate random cryptographic keys. /// - When failing to transform an identity into its corresponding state transition. /// - Conversion and encoding errors related to the cryptographic data. -pub fn create_state_transitions_for_identities( - identities: Vec, +pub fn create_state_transitions_for_identities<'a, I>( + identities: I, amount_range: &AmountRange, signer: &SimpleSigner, rng: &mut StdRng, platform_version: &PlatformVersion, -) -> Vec<(Identity, StateTransition)> { +) -> Vec<(Identity, StateTransition)> +where + I: IntoIterator, +{ identities .into_iter() - .map(|mut identity| { + .map(|identity| { let (_, pk) = ECDSA_SECP256K1 .random_public_and_private_key_data(rng, platform_version) .unwrap(); @@ -1051,7 +1054,7 @@ pub fn create_state_transitions_for_identities( .expect("expected to transform identity into identity create transition"); identity.set_id(identity_create_transition.owner_id()); - (identity, identity_create_transition) + (identity.clone(), identity_create_transition) }) .collect() } diff --git a/packages/token-history-contract/.eslintrc b/packages/token-history-contract/.eslintrc new file mode 100644 index 0000000000..cb6c7636b6 --- /dev/null +++ b/packages/token-history-contract/.eslintrc @@ -0,0 +1,18 @@ +{ + "extends": "airbnb-base", + "rules": { + "no-plusplus": 0, + "eol-last": [ + "error", + "always" + ], + "class-methods-use-this": "off", + "curly": [ + "error", + "all" + ] + }, + "globals": { + "BigInt": true + } +} diff --git a/packages/token-history-contract/.mocharc.yml b/packages/token-history-contract/.mocharc.yml new file mode 100644 index 0000000000..164b941c1b --- /dev/null +++ b/packages/token-history-contract/.mocharc.yml @@ -0,0 +1,2 @@ +require: test/bootstrap.js +recursive: true diff --git a/packages/token-history-contract/Cargo.toml b/packages/token-history-contract/Cargo.toml new file mode 100644 index 0000000000..3625f97a47 --- /dev/null +++ b/packages/token-history-contract/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "token-history-contract" +description = "Token history data contract schema and tools" +version = "1.6.2" +edition = "2021" +rust-version.workspace = true +license = "MIT" + +[dependencies] +thiserror = "1.0.64" +platform-version = { path = "../rs-platform-version" } +serde_json = { version = "1.0" } +platform-value = { path = "../rs-platform-value" } diff --git a/packages/token-history-contract/LICENSE b/packages/token-history-contract/LICENSE new file mode 100644 index 0000000000..3be9583375 --- /dev/null +++ b/packages/token-history-contract/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2019 Dash Core Group, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/token-history-contract/README.md b/packages/token-history-contract/README.md new file mode 100644 index 0000000000..ce6b5a6233 --- /dev/null +++ b/packages/token-history-contract/README.md @@ -0,0 +1,26 @@ +# Wallet Utils Contract + +[![Build Status](https://github.com/dashpay/platform/actions/workflows/release.yml/badge.svg)](https://github.com/dashpay/platform/actions/workflows/release.yml) +[![NPM version](https://img.shields.io/npm/v/@dashevo/wallet-contract.svg?style=flat-square)](https://npmjs.org/package/@dashevo/wallet-contract) + +JSON Contracts for Dash Wallet apps + +## Table of Contents + +- [Install](#install) +- [Contributing](#contributing) +- [License](#license) + +## Install + +```sh +npm install @dashevo/wallet-contract +``` + +## Contributing + +Feel free to dive in! [Open an issue](https://github.com/dashpay/platform/issues/new/choose) or submit PRs. + +## License + +[MIT](LICENSE) © Dash Core Group, Inc. diff --git a/packages/token-history-contract/lib/systemIds.js b/packages/token-history-contract/lib/systemIds.js new file mode 100644 index 0000000000..a89ad1ed75 --- /dev/null +++ b/packages/token-history-contract/lib/systemIds.js @@ -0,0 +1,4 @@ +module.exports = { + ownerId: '11111111111111111111111111111111', + contractId: 'BqzxK9UQdAeXbE7zY78uq6MfWWk3TrXZWfstnMoHZGh1', +}; diff --git a/packages/token-history-contract/package.json b/packages/token-history-contract/package.json new file mode 100644 index 0000000000..def4552747 --- /dev/null +++ b/packages/token-history-contract/package.json @@ -0,0 +1,29 @@ +{ + "name": "@dashevo/token-history-contract", + "version": "1.8.0-dev.2", + "description": "The token history contract", + "scripts": { + "lint": "eslint .", + "test": "yarn run test:unit", + "test:unit": "mocha 'test/unit/**/*.spec.js'" + }, + "contributors": [ + { + "name": "Samuel Westrich", + "email": "sam@dash.org", + "url": "https://github.com/quantumexplorer" + } + ], + "license": "MIT", + "devDependencies": { + "@dashevo/wasm-dpp": "workspace:*", + "chai": "^4.3.10", + "dirty-chai": "^2.0.1", + "eslint": "^8.53.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-plugin-import": "^2.29.0", + "mocha": "^10.2.0", + "sinon": "^17.0.1", + "sinon-chai": "^3.7.0" + } +} 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 new file mode 100644 index 0000000000..0946d7a29e --- /dev/null +++ b/packages/token-history-contract/schema/v1/token-history-contract-documents.json @@ -0,0 +1,580 @@ +{ + "burn": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byDate", + "properties": [ + { + "tokenId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byAmount", + "properties": [ + { + "tokenId": "asc" + }, + { + "amount": "asc" + } + ] + }, + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "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" + }, + "amount": { + "type": "integer", + "minimum": 0, + "description": "The amount that was burned", + "position": 1 + }, + "note": { + "type": "string", + "maxLength": 2048, + "description": "An optional explanation of why this burn took place", + "position": 2 + } + }, + "required": [ + "tokenId", + "amount", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + }, + "mint": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byDate", + "properties": [ + { + "tokenId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byAmount", + "properties": [ + { + "tokenId": "asc" + }, + { + "amount": "asc" + } + ] + }, + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byRecipientId", + "properties": [ + { + "tokenId": "asc" + }, + { + "recipientId": "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" + }, + "recipientId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The token ID", + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier" + }, + "amount": { + "type": "integer", + "minimum": 0, + "description": "The amount that was burned", + "position": 2 + }, + "note": { + "type": "string", + "maxLength": 2048, + "description": "An optional explanation of why this mint took place", + "position": 3 + } + }, + "required": [ + "tokenId", + "amount", + "recipientId", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + }, + "transfer": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byDate", + "properties": [ + { + "tokenId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byAmount", + "properties": [ + { + "tokenId": "asc" + }, + { + "amount": "asc" + } + ] + }, + { + "name": "from", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "to", + "properties": [ + { + "tokenId": "asc" + }, + { + "toIdentityId": "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" + }, + "amount": { + "type": "integer", + "minimum": 0, + "description": "The amount that was burned", + "position": 1 + }, + "toIdentityId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The identity or the group Id", + "position": 2, + "contentMediaType": "application/x.dash.dpp.identifier" + }, + "encryptedPersonalNote": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 2048, + "description": "An optional encrypted explanation of why this transfer took place only meant for the sender", + "position": 3 + }, + "encryptedSharedNote": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 2048, + "description": "An optional encrypted explanation of why this transfer took place shared between the sender and the receiver", + "position": 4 + }, + "publicNote": { + "type": "string", + "maxLength": 2048, + "description": "An optional public explanation of why this transfer took place", + "position": 5 + }, + "senderKeyIndex": { + "type": "integer", + "minimum": 0, + "description": "Used with the encrypted shared note", + "position": 6 + }, + "recipientKeyIndex": { + "type": "integer", + "minimum": 0, + "description": "Used with the encrypted shared note", + "position": 7 + }, + "rootEncryptionKeyIndex": { + "type": "integer", + "minimum": 0, + "description": "Used with the encrypted private note", + "position": 8 + }, + "derivationEncryptionKeyIndex": { + "type": "integer", + "minimum": 0, + "description": "Used with the encrypted private note", + "position": 9 + } + }, + "required": [ + "tokenId", + "amount", + "toIdentityId", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + }, + "freeze": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byFrozenIdentityId", + "properties": [ + { + "tokenId": "asc" + }, + { + "frozenIdentityId": "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" + }, + "frozenIdentityId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The identity Id of the frozen token account", + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier" + } + }, + "required": [ + "tokenId", + "frozenIdentityId", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + }, + "unfreeze": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byFrozenIdentityId", + "properties": [ + { + "tokenId": "asc" + }, + { + "frozenIdentityId": "asc" + }, + { + "$createdAt": "asc" + } + ] + } + ], + "properties": { + "tokenId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The token ID", + "position": 0 + }, + "frozenIdentityId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The identity Id of the frozen token account", + "position": 1 + } + }, + "required": [ + "tokenId", + "frozenIdentityId", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + }, + "destroyFrozenFunds": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byAmount", + "properties": [ + { + "tokenId": "asc" + }, + { + "amount": "asc" + } + ] + }, + { + "name": "byFrozenIdentityId", + "properties": [ + { + "tokenId": "asc" + }, + { + "frozenIdentityId": "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" + }, + "frozenIdentityId": { + "type": "array", + "byteArray": true, + "minItems": 32, + "maxItems": 32, + "description": "The identity Id of the frozen token account", + "position": 1, + "contentMediaType": "application/x.dash.dpp.identifier" + }, + "amount": { + "type": "integer", + "minimum": 0, + "description": "The amount that was frost burned", + "position": 2 + } + }, + "required": [ + "tokenId", + "frozenIdentityId", + "amount", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + }, + "emergencyAction": { + "type": "object", + "documentsMutable": false, + "canBeDeleted": false, + "creationRestrictionMode": 2, + "indices": [ + { + "name": "byOwnerId", + "properties": [ + { + "tokenId": "asc" + }, + { + "$ownerId": "asc" + }, + { + "action": "asc" + }, + { + "$createdAt": "asc" + } + ] + }, + { + "name": "byAction", + "properties": [ + { + "tokenId": "asc" + }, + { + "action": "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" + }, + "action": { + "type": "integer", + "minimum": 0, + "description": "The action we are performing", + "position": 1 + } + }, + "required": [ + "tokenId", + "action", + "$createdAt", + "$createdAtBlockHeight" + ], + "additionalProperties": false + } +} diff --git a/packages/token-history-contract/src/error.rs b/packages/token-history-contract/src/error.rs new file mode 100644 index 0000000000..d01bbcc91c --- /dev/null +++ b/packages/token-history-contract/src/error.rs @@ -0,0 +1,17 @@ +use platform_version::version::FeatureVersion; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + /// Platform expected some specific versions + #[error("platform unknown version on {method}, received: {received}")] + UnknownVersionMismatch { + /// method + method: String, + /// the allowed versions for this method + known_versions: Vec, + /// requested core height + received: FeatureVersion, + }, + #[error("schema deserialize error: {0}")] + InvalidSchemaJson(#[from] serde_json::Error), +} diff --git a/packages/token-history-contract/src/lib.rs b/packages/token-history-contract/src/lib.rs new file mode 100644 index 0000000000..70dafcc26f --- /dev/null +++ b/packages/token-history-contract/src/lib.rs @@ -0,0 +1,37 @@ +mod error; +pub mod v1; + +pub use crate::error::Error; +use platform_value::{Identifier, IdentifierBytes32}; +use platform_version::version::PlatformVersion; +use serde_json::Value; + +pub const ID_BYTES: [u8; 32] = [ + 92, 20, 14, 101, 92, 2, 101, 187, 194, 168, 8, 113, 109, 225, 132, 121, 133, 19, 89, 24, 173, + 81, 205, 253, 11, 118, 102, 75, 169, 91, 163, 124, +]; + +pub const OWNER_ID_BYTES: [u8; 32] = [0; 32]; + +pub const ID: Identifier = Identifier(IdentifierBytes32(ID_BYTES)); +pub const OWNER_ID: Identifier = Identifier(IdentifierBytes32(OWNER_ID_BYTES)); +pub fn load_definitions(platform_version: &PlatformVersion) -> Result, Error> { + match platform_version.system_data_contracts.withdrawals { + 1 => Ok(None), + version => Err(Error::UnknownVersionMismatch { + method: "wallet_contract::load_definitions".to_string(), + known_versions: vec![1], + received: version, + }), + } +} +pub fn load_documents_schemas(platform_version: &PlatformVersion) -> Result { + match platform_version.system_data_contracts.withdrawals { + 1 => v1::load_documents_schemas(), + version => Err(Error::UnknownVersionMismatch { + method: "wallet_contract::load_documents_schemas".to_string(), + known_versions: vec![1], + received: version, + }), + } +} diff --git a/packages/token-history-contract/src/v1/mod.rs b/packages/token-history-contract/src/v1/mod.rs new file mode 100644 index 0000000000..ddd4fa1115 --- /dev/null +++ b/packages/token-history-contract/src/v1/mod.rs @@ -0,0 +1,21 @@ +use crate::Error; +use serde_json::Value; + +pub mod document_types { + pub mod tx_metadata { + pub const NAME: &str = "tx_metadata"; + + pub mod properties { + pub const KEY_INDEX: &str = "keyIndex"; + pub const ENCRYPTION_KEY_INDEX: &str = "encryptionKeyIndex"; + pub const ENCRYPTED_METADATA: &str = "encryptedMetadata"; + } + } +} + +pub fn load_documents_schemas() -> Result { + serde_json::from_str(include_str!( + "../../schema/v1/token-history-contract-documents.json" + )) + .map_err(Error::InvalidSchemaJson) +} diff --git a/packages/token-history-contract/test/.eslintrc b/packages/token-history-contract/test/.eslintrc new file mode 100644 index 0000000000..720ced7385 --- /dev/null +++ b/packages/token-history-contract/test/.eslintrc @@ -0,0 +1,12 @@ +{ + "env": { + "node": true, + "mocha": true + }, + "rules": { + "import/no-extraneous-dependencies": "off" + }, + "globals": { + "expect": true + } +} diff --git a/packages/token-history-contract/test/bootstrap.js b/packages/token-history-contract/test/bootstrap.js new file mode 100644 index 0000000000..7af04f464d --- /dev/null +++ b/packages/token-history-contract/test/bootstrap.js @@ -0,0 +1,30 @@ +const sinon = require('sinon'); +const sinonChai = require('sinon-chai'); + +const { expect, use } = require('chai'); +const dirtyChai = require('dirty-chai'); + +const { + default: loadWasmDpp, +} = require('@dashevo/wasm-dpp'); + +use(dirtyChai); +use(sinonChai); + +exports.mochaHooks = { + beforeAll: loadWasmDpp, + + beforeEach() { + if (!this.sinon) { + this.sinon = sinon.createSandbox(); + } else { + this.sinon.restore(); + } + }, + + afterEach() { + this.sinon.restore(); + }, +}; + +global.expect = expect; diff --git a/packages/token-history-contract/test/unit/tokenHistoryContract.spec.js b/packages/token-history-contract/test/unit/tokenHistoryContract.spec.js new file mode 100644 index 0000000000..3900303dd1 --- /dev/null +++ b/packages/token-history-contract/test/unit/tokenHistoryContract.spec.js @@ -0,0 +1,451 @@ +const crypto = require('crypto'); +const { + DashPlatformProtocol, + JsonSchemaError, +} = require('@dashevo/wasm-dpp'); +const generateRandomIdentifier = require('@dashevo/wasm-dpp/lib/test/utils/generateRandomIdentifierAsync'); +const { expect } = require('chai'); +const tokenHistoryContractDocumentsSchema = require('../../schema/v1/token-history-contract-documents.json'); + +const expectJsonSchemaError = (validationResult, errorCount = 1) => { + const errors = validationResult.getErrors(); + expect(errors) + .to + .have + .length(errorCount); + + const error = validationResult.getErrors()[0]; + expect(error) + .to + .be + .instanceof(JsonSchemaError); + + return error; +}; + +describe('Token History Contract', () => { + let dpp; + let dataContract; + let identityId; + + beforeEach(async () => { + dpp = new DashPlatformProtocol({ generate: () => crypto.randomBytes(32) }); + identityId = await generateRandomIdentifier(); + dataContract = dpp.dataContract.create(identityId, BigInt(1), tokenHistoryContractDocumentsSchema); + }); + + it('should have a valid contract definition', async () => { + expect(() => dpp.dataContract.create(identityId, BigInt(1), tokenHistoryContractDocumentsSchema)) + .to + .not + .throw(); + }); + + describe('documents', () => { + describe('burn', () => { + let rawBurnDocument; + + beforeEach(() => { + rawBurnDocument = { + tokenId: crypto.randomBytes(32), + amount: 100, + note: 'Burning tokens', + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 42, + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawBurnDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + + it('should be 32 bytes', async () => { + rawBurnDocument.tokenId = crypto.randomBytes(31); + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minItems'); + expect(error.instancePath).to.equal('/tokenId'); + }); + }); + + describe('amount', () => { + it('should be defined', async () => { + delete rawBurnDocument.amount; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('amount'); + }); + + it('should be a non-negative integer', async () => { + rawBurnDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + describe('$createdAt / $createdAtBlockHeight', () => { + it('should be defined', async () => { + delete rawBurnDocument.$createdAt; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('$createdAt'); + }); + }); + + it('should not have additional properties', async () => { + rawBurnDocument.extraProp = 123; + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['extraProp']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'burn', rawBurnDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('mint', () => { + let rawMintDocument; + + beforeEach(() => { + rawMintDocument = { + tokenId: crypto.randomBytes(32), + recipientId: crypto.randomBytes(32), + amount: 1000, + note: 'Minting tokens', + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 50, + }; + }); + + describe('tokenId', () => { + it('should be 32 bytes', async () => { + rawMintDocument.tokenId = crypto.randomBytes(31); + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minItems'); + expect(error.instancePath).to.equal('/tokenId'); + }); + }); + + describe('recipientId', () => { + it('should be defined', async () => { + delete rawMintDocument.recipientId; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('recipientId'); + }); + + it('should be 32 bytes', async () => { + rawMintDocument.recipientId = crypto.randomBytes(31); + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minItems'); + expect(error.instancePath).to.equal('/recipientId'); + }); + }); + + describe('amount', () => { + it('should be a non-negative integer', async () => { + rawMintDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + it('should not have additional properties', async () => { + rawMintDocument.extraField = 'foo'; + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['extraField']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'mint', rawMintDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('transfer', () => { + let rawTransferDocument; + + beforeEach(() => { + rawTransferDocument = { + tokenId: crypto.randomBytes(32), + amount: 10, + toIdentityId: crypto.randomBytes(32), + publicNote: 'Transfer tokens', + encryptedPersonalNote: crypto.randomBytes(32), + encryptedSharedNote: crypto.randomBytes(32), + senderKeyIndex: 0, + recipientKeyIndex: 1, + rootEncryptionKeyIndex: 2, + derivationEncryptionKeyIndex: 3, + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 100, + }; + }); + + describe('tokenId', () => { + it('should be 32 bytes', async () => { + rawTransferDocument.tokenId = crypto.randomBytes(31); + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minItems'); + expect(error.instancePath).to.equal('/tokenId'); + }); + }); + + describe('amount', () => { + it('should be a non-negative integer', async () => { + rawTransferDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + describe('toIdentityId', () => { + it('should be defined', async () => { + delete rawTransferDocument.toIdentityId; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('toIdentityId'); + }); + }); + + it('should not have additional properties', async () => { + rawTransferDocument.foo = 'bar'; + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['foo']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'transfer', rawTransferDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('freeze', () => { + let rawFreezeDocument; + + beforeEach(() => { + rawFreezeDocument = { + tokenId: crypto.randomBytes(32), + frozenIdentityId: crypto.randomBytes(32), + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 123, + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawFreezeDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('frozenIdentityId', () => { + it('should be 32 bytes', async () => { + rawFreezeDocument.frozenIdentityId = crypto.randomBytes(31); + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minItems'); + expect(error.instancePath).to.equal('/frozenIdentityId'); + }); + }); + + it('should not have additional properties', async () => { + rawFreezeDocument.something = true; + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['something']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'freeze', rawFreezeDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('unfreeze', () => { + let rawUnfreezeDocument; + + beforeEach(() => { + rawUnfreezeDocument = { + tokenId: crypto.randomBytes(32), + frozenIdentityId: crypto.randomBytes(32), + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 150, + }; + }); + + describe('tokenId', () => { + it('should be 32 bytes', async () => { + rawUnfreezeDocument.tokenId = crypto.randomBytes(33); + const document = dpp.document.create(dataContract, identityId, 'unfreeze', rawUnfreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('maxItems'); + expect(error.instancePath).to.equal('/tokenId'); + }); + }); + + it('should not have additional properties', async () => { + rawUnfreezeDocument.foo = 'bar'; + const document = dpp.document.create(dataContract, identityId, 'unfreeze', rawUnfreezeDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['foo']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'unfreeze', rawUnfreezeDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('destroyFrozenFunds', () => { + let rawDestroyFrozenFundsDocument; + + beforeEach(() => { + rawDestroyFrozenFundsDocument = { + tokenId: crypto.randomBytes(32), + frozenIdentityId: crypto.randomBytes(32), + amount: 500, + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 222, + }; + }); + + describe('frozenIdentityId', () => { + it('should be 32 bytes', async () => { + rawDestroyFrozenFundsDocument.frozenIdentityId = crypto.randomBytes(31); + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minItems'); + expect(error.instancePath).to.equal('/frozenIdentityId'); + }); + }); + + describe('amount', () => { + it('should be non-negative', async () => { + rawDestroyFrozenFundsDocument.amount = -1; + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + it('should not have additional properties', async () => { + rawDestroyFrozenFundsDocument.bar = 123; + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['bar']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'destroyFrozenFunds', rawDestroyFrozenFundsDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + + describe('emergencyAction', () => { + let rawEmergencyActionDocument; + + beforeEach(() => { + rawEmergencyActionDocument = { + tokenId: crypto.randomBytes(32), + action: 1, + $createdAt: Math.ceil(Date.now() / 1000), + $createdAtBlockHeight: 300, + }; + }); + + describe('tokenId', () => { + it('should be defined', async () => { + delete rawEmergencyActionDocument.tokenId; + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('required'); + expect(error.params.missingProperty).to.equal('tokenId'); + }); + }); + + describe('action', () => { + it('should be non-negative', async () => { + rawEmergencyActionDocument.action = -5; + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('minimum'); + }); + }); + + it('should not have additional properties', async () => { + rawEmergencyActionDocument.xyz = 999; + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = document.validate(dpp.protocolVersion); + const error = expectJsonSchemaError(validationResult); + expect(error.keyword).to.equal('additionalProperties'); + expect(error.params.additionalProperties).to.deep.equal(['xyz']); + }); + + it('should be valid', async () => { + const document = dpp.document.create(dataContract, identityId, 'emergencyAction', rawEmergencyActionDocument); + const validationResult = await document.validate(dpp.protocolVersion); + expect(validationResult.isValid()).to.be.true(); + }); + }); + }); +}); \ No newline at end of file diff --git a/packages/wasm-dpp/src/document/document_facade.rs b/packages/wasm-dpp/src/document/document_facade.rs index 609794eaa9..6255dfe2df 100644 --- a/packages/wasm-dpp/src/document/document_facade.rs +++ b/packages/wasm-dpp/src/document/document_facade.rs @@ -4,7 +4,7 @@ use wasm_bindgen::{prelude::*, JsValue}; use crate::document::factory::DocumentFactoryWASM; use crate::{DataContractWasm, ExtendedDocumentWasm}; -use crate::document::state_transition::document_batch_transition::DocumentsBatchTransitionWasm; +use crate::document::state_transition::batch_transition::BatchTransitionWasm; #[derive(Clone)] #[wasm_bindgen(js_name=DocumentFacade)] @@ -96,7 +96,7 @@ impl DocumentFacadeWasm { &self, documents: &JsValue, nonce_counter_value: &js_sys::Object, //IdentityID/ContractID -> nonce - ) -> Result { + ) -> Result { self.factory .create_state_transition(documents, nonce_counter_value) } diff --git a/packages/wasm-dpp/src/document/errors/document_already_exists_error.rs b/packages/wasm-dpp/src/document/errors/document_already_exists_error.rs index 111d138b8d..a4b028f726 100644 --- a/packages/wasm-dpp/src/document/errors/document_already_exists_error.rs +++ b/packages/wasm-dpp/src/document/errors/document_already_exists_error.rs @@ -1,5 +1,5 @@ // use crate::document::state_transition::document_batch_transition::document_transition::from_document_transition_to_js_value; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use dpp::state_transition::batch_transition::batched_transition::document_transition::DocumentTransition; use thiserror::Error; use super::*; diff --git a/packages/wasm-dpp/src/document/errors/document_not_provided_error.rs b/packages/wasm-dpp/src/document/errors/document_not_provided_error.rs index 769f1853c4..bc52033244 100644 --- a/packages/wasm-dpp/src/document/errors/document_not_provided_error.rs +++ b/packages/wasm-dpp/src/document/errors/document_not_provided_error.rs @@ -1,5 +1,5 @@ // use crate::document::state_transition::document_batch_transition::document_transition::from_document_transition_to_js_value; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use dpp::state_transition::batch_transition::batched_transition::document_transition::DocumentTransition; use thiserror::Error; use super::*; diff --git a/packages/wasm-dpp/src/document/errors/invalid_document_action_error.rs b/packages/wasm-dpp/src/document/errors/invalid_document_action_error.rs index 0496d71c07..78eb5d5d05 100644 --- a/packages/wasm-dpp/src/document/errors/invalid_document_action_error.rs +++ b/packages/wasm-dpp/src/document/errors/invalid_document_action_error.rs @@ -1,9 +1,9 @@ // use crate::document::state_transition::document_batch_transition::document_transition::from_document_transition_to_js_value; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransition; +use dpp::state_transition::batch_transition::batched_transition::document_transition::DocumentTransition; use thiserror::Error; use super::*; -use dpp::state_transition::documents_batch_transition::document_transition::action_type::TransitionActionTypeGetter; +use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionTypeGetter; #[wasm_bindgen] #[derive(Error, Debug)] diff --git a/packages/wasm-dpp/src/document/factory.rs b/packages/wasm-dpp/src/document/factory.rs index 0b927a6080..639aaa2324 100644 --- a/packages/wasm-dpp/src/document/factory.rs +++ b/packages/wasm-dpp/src/document/factory.rs @@ -14,11 +14,11 @@ use dpp::document::Document; use dpp::prelude::ExtendedDocument; use dpp::identifier::Identifier; -use dpp::state_transition::documents_batch_transition::document_transition::action_type::DocumentTransitionActionType; +use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionType; use dpp::version::PlatformVersion; use std::convert::TryFrom; -use crate::document_batch_transition::DocumentsBatchTransitionWasm; +use crate::batch_transition::BatchTransitionWasm; use crate::entropy_generator::ExternalEntropyGenerator; use crate::{ identifier::identifier_from_js_value, @@ -109,7 +109,7 @@ impl DocumentFactoryWASM { &self, documents: &JsValue, nonce_counter_value: &js_sys::Object, //IdentityID/ContractID -> nonce - ) -> Result { + ) -> Result { let mut nonce_counter = BTreeMap::new(); let mut contract_ids_to_check = HashSet::<&Identifier>::new(); diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/batched_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/batched_transition/mod.rs new file mode 100644 index 0000000000..d83ae4d473 --- /dev/null +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/batched_transition/mod.rs @@ -0,0 +1,18 @@ +use dpp::state_transition::batch_transition::batched_transition::BatchedTransition; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(js_name=BatchedTransition)] +#[derive(Debug, Clone)] +pub struct BatchedTransitionWasm(BatchedTransition); + +impl From for BatchedTransitionWasm { + fn from(t: BatchedTransition) -> Self { + BatchedTransitionWasm(t) + } +} + +impl From for BatchedTransition { + fn from(t: BatchedTransitionWasm) -> Self { + t.0 + } +} diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_create_transition.rs similarity index 98% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_create_transition.rs index 8cf7b5d0b9..4a5218e30e 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_create_transition.rs @@ -1,6 +1,6 @@ use dpp::prelude::Revision; -use dpp::state_transition::documents_batch_transition::document_create_transition::DocumentCreateTransition; +use dpp::state_transition::batch_transition::document_create_transition::DocumentCreateTransition; use dpp::document::INITIAL_REVISION; diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_delete_transition.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_delete_transition.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_delete_transition.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_delete_transition.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_replace_transition.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_replace_transition.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_replace_transition.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/document_replace_transition.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs similarity index 90% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs index a26d579d7d..d256c15c60 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/document_transition/mod.rs @@ -7,13 +7,12 @@ mod document_create_transition; // pub use document_replace_transition::*; use dpp::platform_value::Value; -use dpp::state_transition::documents_batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; -use dpp::state_transition::documents_batch_transition::document_transition::action_type::TransitionActionTypeGetter; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransitionV0Methods; -use dpp::{ - state_transition::documents_batch_transition::document_transition::DocumentTransition, - util::json_value::JsonValueExt, ProtocolError, +use dpp::state_transition::batch_transition::batched_transition::document_transition::{ + DocumentTransition, DocumentTransitionV0Methods, }; +use dpp::state_transition::batch_transition::batched_transition::document_transition_action_type::DocumentTransitionActionTypeGetter; +use dpp::state_transition::batch_transition::document_create_transition::v0::v0_methods::DocumentCreateTransitionV0Methods; +use dpp::{util::json_value::JsonValueExt, ProtocolError}; use serde::Serialize; use serde_json::Value as JsonValue; use wasm_bindgen::prelude::*; diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/mod.rs similarity index 89% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/mod.rs index d0ebb9ae56..6dfadbf985 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/mod.rs @@ -12,9 +12,8 @@ use dpp::consensus::signature::SignatureError; use dpp::consensus::ConsensusError; use dpp::platform_value::BinaryData; use dpp::serialization::PlatformSerializable; -use dpp::state_transition::documents_batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; -use dpp::state_transition::documents_batch_transition::document_transition::DocumentTransition; -use dpp::state_transition::documents_batch_transition::DocumentsBatchTransition; +use dpp::state_transition::batch_transition::accessors::DocumentsBatchTransitionAccessorsV0; +use dpp::state_transition::batch_transition::BatchTransition; use dpp::state_transition::StateTransition; use wasm_bindgen::prelude::*; @@ -26,17 +25,21 @@ use crate::{ IdentityPublicKeyWasm, }; -use document_transition::DocumentTransitionWasm; -use dpp::state_transition::documents_batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use dpp::ed25519_dalek::ed25519::signature::SignerMut; +use dpp::state_transition::batch_transition::batched_transition::BatchedTransition; +use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use crate::batch_transition::batched_transition::BatchedTransitionWasm; use dpp::state_transition::StateTransitionIdentitySigned; +mod batched_transition; pub mod document_transition; +mod token_transition; // pub mod validation; #[derive(Clone, Debug)] -#[wasm_bindgen(js_name = DocumentsBatchTransition)] -pub struct DocumentsBatchTransitionWasm(DocumentsBatchTransition); +#[wasm_bindgen(js_name = BatchTransition)] +pub struct BatchTransitionWasm(BatchTransition); #[derive(Debug, Serialize, Deserialize, Default, Clone, Copy)] #[serde(rename_all = "camelCase")] @@ -47,8 +50,8 @@ pub struct ToObjectOptions { skip_identifiers_conversion: bool, } -#[wasm_bindgen(js_class=DocumentsBatchTransition)] -impl DocumentsBatchTransitionWasm { +#[wasm_bindgen(js_class=BatchTransition)] +impl BatchTransitionWasm { // #[wasm_bindgen(constructor)] // pub fn from_object( // js_raw_transition: JsValue, @@ -90,7 +93,7 @@ impl DocumentsBatchTransitionWasm { #[wasm_bindgen(js_name=getType)] pub fn get_type(&self) -> u8 { - StateTransitionType::DocumentsBatch.into() + StateTransitionType::Batch.into() } #[wasm_bindgen(js_name=getOwnerId)] @@ -101,10 +104,9 @@ impl DocumentsBatchTransitionWasm { #[wasm_bindgen(js_name=getTransitions)] pub fn get_transitions(&self) -> js_sys::Array { let array = js_sys::Array::new(); - let transitions = self.0.transitions(); - for tr in transitions.iter().cloned() { - let transition: DocumentTransitionWasm = tr.into(); + for tr in self.0.transitions_iter() { + let transition: BatchedTransitionWasm = tr.to_owned_transition().into(); array.push(&transition.into()); } @@ -115,8 +117,8 @@ impl DocumentsBatchTransitionWasm { pub fn set_transitions(&mut self, js_transitions: Array) -> Result<(), JsValue> { let mut transitions = vec![]; for js_transition in js_transitions.iter() { - let transition: DocumentTransition = js_transition - .to_wasm::("DocumentTransition")? + let transition: BatchedTransition = js_transition + .to_wasm::("BatchedTransition")? .to_owned() .into(); transitions.push(transition) @@ -276,7 +278,7 @@ impl DocumentsBatchTransitionWasm { let bls_adapter = BlsAdapter(bls); // TODO: come up with a better way to set signature to the binding. - let mut state_transition = StateTransition::DocumentsBatch(self.0.clone()); + let mut state_transition = StateTransition::Batch(self.0.clone()); state_transition .sign( &identity_public_key.to_owned().into(), @@ -322,7 +324,7 @@ impl DocumentsBatchTransitionWasm { ) -> Result { let bls_adapter = BlsAdapter(bls); - let verification_result = StateTransition::DocumentsBatch(self.0.clone()) + let verification_result = StateTransition::Batch(self.0.clone()) .verify_signature(&identity_public_key.to_owned().into(), &bls_adapter); match verification_result { @@ -402,10 +404,9 @@ impl DocumentsBatchTransitionWasm { #[wasm_bindgen(js_name=toBuffer)] pub fn to_buffer(&self) -> Result { - let bytes = PlatformSerializable::serialize_to_bytes(&StateTransition::DocumentsBatch( - self.0.clone(), - )) - .with_js_error()?; + let bytes = + PlatformSerializable::serialize_to_bytes(&StateTransition::Batch(self.0.clone())) + .with_js_error()?; Ok(Buffer::from_bytes(&bytes)) } @@ -423,14 +424,14 @@ impl DocumentsBatchTransitionWasm { // } } -impl From for DocumentsBatchTransitionWasm { - fn from(t: DocumentsBatchTransition) -> Self { - DocumentsBatchTransitionWasm(t) +impl From for BatchTransitionWasm { + fn from(t: BatchTransition) -> Self { + BatchTransitionWasm(t) } } -impl From for DocumentsBatchTransition { - fn from(t: DocumentsBatchTransitionWasm) -> Self { +impl From for BatchTransition { + fn from(t: BatchTransitionWasm) -> Self { t.0 } } diff --git a/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs new file mode 100644 index 0000000000..7b10fb55c1 --- /dev/null +++ b/packages/wasm-dpp/src/document/state_transition/batch_transition/token_transition/mod.rs @@ -0,0 +1,18 @@ +use dpp::state_transition::batch_transition::batched_transition::token_transition::TokenTransition; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen(js_name=TokenTransition)] +#[derive(Debug, Clone)] +pub struct TokenTransitionWasm(TokenTransition); + +impl From for TokenTransitionWasm { + fn from(t: TokenTransition) -> Self { + TokenTransitionWasm(t) + } +} + +impl From for TokenTransition { + fn from(t: TokenTransitionWasm) -> Self { + t.0 + } +} diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/find_duplicates_by_id.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/find_duplicates_by_id.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/find_duplicates_by_id.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/find_duplicates_by_id.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/find_duplicates_by_indices.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/find_duplicates_by_indices.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/find_duplicates_by_indices.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/find_duplicates_by_indices.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/mod.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/mod.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/mod.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/validate_documents_batch_transition_basic.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/validate_documents_batch_transition_basic.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/validate_documents_batch_transition_basic.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/validate_documents_batch_transition_basic.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/validate_partial_compound_indices.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/validate_partial_compound_indices.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/basic/validate_partial_compound_indices.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/basic/validate_partial_compound_indices.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/mod.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/mod.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/mod.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/fetch_extended_documents.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/fetch_extended_documents.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/fetch_extended_documents.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/fetch_extended_documents.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/mod.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/mod.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/mod.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/mod.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/validate_documents_batch_transitions_state.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/validate_documents_batch_transitions_state.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/validate_documents_batch_transitions_state.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/validate_documents_batch_transitions_state.rs diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/validate_documents_uniqueness_by_indices.rs b/packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/validate_documents_uniqueness_by_indices.rs similarity index 100% rename from packages/wasm-dpp/src/document/state_transition/document_batch_transition/validation/state/validate_documents_uniqueness_by_indices.rs rename to packages/wasm-dpp/src/document/state_transition/batch_transition/validation/state/validate_documents_uniqueness_by_indices.rs diff --git a/packages/wasm-dpp/src/document/state_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/mod.rs index 7db6d118e0..03238bee69 100644 --- a/packages/wasm-dpp/src/document/state_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/mod.rs @@ -1 +1 @@ -pub mod document_batch_transition; +pub mod batch_transition; diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 627b65a267..c3105e3187 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -61,10 +61,12 @@ use dpp::consensus::state::data_trigger::DataTriggerError::{ DataTriggerConditionError, DataTriggerExecutionError, DataTriggerInvalidResultError, }; use wasm_bindgen::{JsError, JsValue}; -use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, InvalidDocumentTypeRequiredSecurityLevelError, UnknownDocumentCreationRestrictionModeError, UnknownSecurityLevelError, UnknownStorageKeyRequirementsError, UnknownTradeModeError, UnknownTransferableTypeError}; +use dpp::consensus::basic::data_contract::{ContestedUniqueIndexOnMutableDocumentTypeError, ContestedUniqueIndexWithUniqueIndexError, DataContractTokenConfigurationUpdateError, 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::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; @@ -73,12 +75,15 @@ use dpp::consensus::state::document::document_contest_not_joinable_error::Docume use dpp::consensus::state::document::document_contest_not_paid_for_error::DocumentContestNotPaidForError; use dpp::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError; use dpp::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError; +use dpp::consensus::state::group::{GroupActionAlreadyCompletedError, GroupActionAlreadySignedByIdentityError, GroupActionDoesNotExistError, IdentityNotMemberOfGroupError}; use dpp::consensus::state::identity::identity_public_key_already_exists_for_unique_contract_bounds_error::IdentityPublicKeyAlreadyExistsForUniqueContractBoundsError; use dpp::consensus::state::identity::master_public_key_update_error::MasterPublicKeyUpdateError; use dpp::consensus::state::identity::missing_transfer_key_error::MissingTransferKeyError; use dpp::consensus::state::identity::no_transfer_key_for_core_withdrawal_available_error::NoTransferKeyForCoreWithdrawalAvailableError; +use dpp::consensus::state::identity::RecipientIdentityDoesNotExistError; use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_insufficient_error::PrefundedSpecializedBalanceInsufficientError; use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError; +use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, UnauthorizedTokenActionError}; use dpp::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError; use dpp::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError; use dpp::consensus::state::voting::masternode_not_found_error::MasternodeNotFoundError; @@ -308,6 +313,33 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::DocumentContestNotPaidForError(e) => { generic_consensus_error!(DocumentContestNotPaidForError, e).into() } + StateError::RecipientIdentityDoesNotExistError(e) => { + generic_consensus_error!(RecipientIdentityDoesNotExistError, e).into() + } + StateError::IdentityDoesNotHaveEnoughTokenBalanceError(e) => { + generic_consensus_error!(IdentityDoesNotHaveEnoughTokenBalanceError, e).into() + } + StateError::UnauthorizedTokenActionError(e) => { + generic_consensus_error!(UnauthorizedTokenActionError, e).into() + } + StateError::IdentityTokenAccountFrozenError(e) => { + generic_consensus_error!(IdentityTokenAccountFrozenError, e).into() + } + StateError::IdentityNotMemberOfGroupError(e) => { + generic_consensus_error!(IdentityNotMemberOfGroupError, e).into() + } + StateError::GroupActionDoesNotExistError(e) => { + generic_consensus_error!(GroupActionDoesNotExistError, e).into() + } + StateError::GroupActionAlreadyCompletedError(e) => { + generic_consensus_error!(GroupActionAlreadyCompletedError, e).into() + } + StateError::GroupActionAlreadySignedByIdentityError(e) => { + generic_consensus_error!(GroupActionAlreadySignedByIdentityError, e).into() + } + StateError::IdentityTokenAccountNotFrozenError(e) => { + generic_consensus_error!(IdentityTokenAccountNotFrozenError, e).into() + } } } @@ -571,6 +603,49 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { ) .into() } + BasicError::DataContractTokenConfigurationUpdateError(e) => { + generic_consensus_error!(DataContractTokenConfigurationUpdateError, e).into() + } + BasicError::InvalidTokenIdError(e) => { + generic_consensus_error!(InvalidTokenIdError, e).into() + } + + BasicError::InvalidTokenPositionError(e) => { + generic_consensus_error!(InvalidTokenPositionError, e).into() + } + + BasicError::ContractHasNoTokensError(e) => { + generic_consensus_error!(ContractHasNoTokensError, e).into() + } + + BasicError::InvalidGroupPositionError(e) => { + generic_consensus_error!(InvalidGroupPositionError, e).into() + } + + BasicError::InvalidActionIdError(e) => { + generic_consensus_error!(InvalidActionIdError, e).into() + } + BasicError::NonContiguousContractTokenPositionsError(e) => { + generic_consensus_error!(NonContiguousContractTokenPositionsError, e).into() + } + BasicError::NonContiguousContractGroupPositionsError(e) => { + generic_consensus_error!(NonContiguousContractGroupPositionsError, e).into() + } + BasicError::InvalidTokenBaseSupplyError(e) => { + generic_consensus_error!(InvalidTokenBaseSupplyError, e).into() + } + BasicError::TokenTransferToOurselfError(e) => { + generic_consensus_error!(TokenTransferToOurselfError, e).into() + } + BasicError::DestinationIdentityForTokenMintingNotSetError(e) => { + generic_consensus_error!(DestinationIdentityForTokenMintingNotSetError, e).into() + } + BasicError::ChoosingTokenMintRecipientNotAllowedError(e) => { + generic_consensus_error!(ChoosingTokenMintRecipientNotAllowedError, e).into() + } + BasicError::GroupActionNotAllowedOnTransitionError(e) => { + generic_consensus_error!(GroupActionNotAllowedOnTransitionError, e).into() + } } } diff --git a/packages/wasm-dpp/src/identity/state_transition/transition_types.rs b/packages/wasm-dpp/src/identity/state_transition/transition_types.rs index 1a4942726e..1fa4ee3dd9 100644 --- a/packages/wasm-dpp/src/identity/state_transition/transition_types.rs +++ b/packages/wasm-dpp/src/identity/state_transition/transition_types.rs @@ -19,7 +19,7 @@ impl From for StateTransitionTypeWasm { fn from(state_transition_type: StateTransitionType) -> Self { match state_transition_type { StateTransitionType::DataContractCreate => StateTransitionTypeWasm::DataContractCreate, - StateTransitionType::DocumentsBatch => StateTransitionTypeWasm::DocumentsBatch, + StateTransitionType::Batch => StateTransitionTypeWasm::DocumentsBatch, StateTransitionType::IdentityCreate => StateTransitionTypeWasm::IdentityCreate, StateTransitionType::IdentityTopUp => StateTransitionTypeWasm::IdentityTopUp, StateTransitionType::DataContractUpdate => StateTransitionTypeWasm::DataContractUpdate, diff --git a/packages/wasm-dpp/src/state_transition/state_transition_factory.rs b/packages/wasm-dpp/src/state_transition/state_transition_factory.rs index 8b3f8bfa86..2ba1a0e025 100644 --- a/packages/wasm-dpp/src/state_transition/state_transition_factory.rs +++ b/packages/wasm-dpp/src/state_transition/state_transition_factory.rs @@ -1,5 +1,5 @@ +use crate::batch_transition::BatchTransitionWasm; use crate::data_contract::{DataContractCreateTransitionWasm, DataContractUpdateTransitionWasm}; -use crate::document_batch_transition::DocumentsBatchTransitionWasm; use crate::errors::from_dpp_err; use crate::identity::state_transition::{ IdentityCreateTransitionWasm, IdentityCreditTransferTransitionWasm, @@ -56,9 +56,7 @@ impl StateTransitionFactoryWasm { StateTransition::IdentityCreditWithdrawal(st) => { Ok(IdentityCreditWithdrawalTransitionWasm::from(st).into()) } - StateTransition::DocumentsBatch(st) => { - Ok(DocumentsBatchTransitionWasm::from(st).into()) - } + StateTransition::Batch(st) => Ok(BatchTransitionWasm::from(st).into()), StateTransition::MasternodeVote(st) => { Ok(MasternodeVoteTransitionWasm::from(st).into()) } From 022030275eda1221166c7336071c335e419d1175 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Sun, 19 Jan 2025 14:43:51 +0700 Subject: [PATCH 2/2] feat(platform): proof verification for many queries and a few more queries (#2431) --- Cargo.lock | 18 +- .../protos/platform/v0/platform.proto | 31 ++ packages/rs-dpp/src/balances/credits.rs | 3 + packages/rs-dpp/src/balances/mod.rs | 1 + .../total_single_token_balance/mod.rs | 49 +++ .../v0/mod.rs | 2 +- packages/rs-drive-abci/src/query/service.rs | 31 +- .../src/query/token_queries/mod.rs | 1 + .../query/token_queries/token_status/mod.rs | 2 +- .../token_queries/token_total_supply/mod.rs | 59 +++ .../token_total_supply/v0/mod.rs | 81 ++++ packages/rs-drive/Cargo.toml | 12 +- .../v0/mod.rs | 2 +- .../fetch_identity_token_balances/v0/mod.rs | 22 +- .../prove_identity_token_balances/v0/mod.rs | 359 +++++++++++++++++- .../src/drive/tokens/balance/queries.rs | 50 ++- .../calculate_total_tokens_balance/mod.rs | 12 +- .../calculate_total_tokens_balance/v0/mod.rs | 8 +- .../info/fetch_identity_token_infos/v0/mod.rs | 22 +- .../info/prove_identity_token_infos/v0/mod.rs | 262 ++++++++++++- .../rs-drive/src/drive/tokens/info/queries.rs | 42 +- .../status/fetch_token_statuses/v0/mod.rs | 18 +- .../status/prove_token_statuses/v0/mod.rs | 201 +++++++++- .../mod.rs | 74 ++++ .../v0/mod.rs | 75 ++++ .../system/fetch_token_total_supply/mod.rs | 69 ++++ .../system/fetch_token_total_supply/v0/mod.rs | 72 ++++ .../rs-drive/src/drive/tokens/system/mod.rs | 3 + .../mod.rs | 40 ++ .../v0/mod.rs | 257 +++++++++++++ packages/rs-drive/src/error/proof.rs | 8 + packages/rs-drive/src/verify/tokens/mod.rs | 4 + .../mod.rs | 75 ++++ .../v0/mod.rs | 72 ++++ .../verify_token_infos_for_identity_id/mod.rs | 74 ++++ .../v0/mod.rs | 74 ++++ .../tokens/verify_token_statuses/mod.rs | 68 ++++ .../tokens/verify_token_statuses/v0/mod.rs | 65 ++++ .../mod.rs | 69 ++++ .../v0/mod.rs | 73 ++++ packages/rs-platform-version/Cargo.toml | 2 +- .../drive_abci_query_versions/mod.rs | 1 + .../drive_abci_query_versions/v1.rs | 5 + .../drive_token_method_versions/mod.rs | 3 + .../drive_token_method_versions/v1.rs | 3 + .../drive_verify_method_versions/mod.rs | 3 + .../drive_verify_method_versions/v1.rs | 3 + .../src/version/mocks/v2_test.rs | 5 + 48 files changed, 2354 insertions(+), 131 deletions(-) create mode 100644 packages/rs-dpp/src/balances/total_single_token_balance/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/token_total_supply/mod.rs create mode 100644 packages/rs-drive-abci/src/query/token_queries/token_total_supply/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs create mode 100644 packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_statuses/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs create mode 100644 packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/v0/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 930e2769ba..5964aaa3fb 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=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" dependencies = [ "axum", "bincode", @@ -2130,7 +2130,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" 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=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" 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=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" dependencies = [ "bincode", "blake3", @@ -2175,7 +2175,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" dependencies = [ "hex", ] @@ -2183,7 +2183,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "3.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" 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=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" 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=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" 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=d8ae2d95f56381b4d104d3983b2f11ae3a968dc7#d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" +source = "git+https://github.com/dashpay/grovedb?rev=e3ac3f7883bb0f2e25936153f76d447b42ebc9c0#e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" 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 81da114443..76b2cce105 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -60,7 +60,9 @@ service Platform { rpc getIdentityTokenInfos(GetIdentityTokenInfosRequest) returns (GetIdentityTokenInfosResponse); rpc getIdentitiesTokenInfos(GetIdentitiesTokenInfosRequest) returns (GetIdentitiesTokenInfosResponse); rpc getTokenStatuses(GetTokenStatusesRequest) returns (GetTokenStatusesResponse); + rpc getTokenTotalSupply(GetTokenTotalSupplyRequest) returns (GetTokenTotalSupplyResponse); rpc getGroupInfo(GetGroupInfoRequest) returns (GetGroupInfoResponse); + rpc getGroupInfos(GetGroupInfosRequest) returns (GetGroupInfosResponse); // rpc getActiveGroupActions(GetActiveGroupActionsRequest) returns (GetActiveGroupActionsResponse); // rpc getClosedGroupActions(GetClosedGroupActionsRequest) returns (GetClosedGroupActionsResponse); } @@ -1398,6 +1400,35 @@ message GetTokenStatusesResponse { } } +message GetTokenTotalSupplyRequest { + message GetTokenTotalSupplyRequestV0 { + bytes token_id = 1; + bool prove = 2; + } + oneof version { + GetTokenTotalSupplyRequestV0 v0 = 1; + } +} + +message GetTokenTotalSupplyResponse { + message GetTokenTotalSupplyResponseV0 { + message TokenTotalSupplyEntry { + bytes token_id = 1; + uint64 total_aggregated_amount_in_user_accounts = 2; + uint64 total_system_amount = 3; + } + + oneof result { + TokenTotalSupplyEntry token_total_supply = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { + GetTokenTotalSupplyResponseV0 v0 = 1; + } +} + message GetGroupInfoRequest { message GetGroupInfoRequestV0 { bytes contract_id = 1; diff --git a/packages/rs-dpp/src/balances/credits.rs b/packages/rs-dpp/src/balances/credits.rs index 4376686a96..c69a02668f 100644 --- a/packages/rs-dpp/src/balances/credits.rs +++ b/packages/rs-dpp/src/balances/credits.rs @@ -22,6 +22,9 @@ pub type Credits = u64; /// Token Amount type pub type TokenAmount = u64; +/// Signed Token Amount type +pub type SignedTokenAmount = i64; + /// Sum token amount pub type SumTokenAmount = i128; diff --git a/packages/rs-dpp/src/balances/mod.rs b/packages/rs-dpp/src/balances/mod.rs index c0f505ac78..6878bd6d8b 100644 --- a/packages/rs-dpp/src/balances/mod.rs +++ b/packages/rs-dpp/src/balances/mod.rs @@ -1,4 +1,5 @@ pub mod total_credits_balance; pub mod credits; +pub mod total_single_token_balance; pub mod total_tokens_balance; diff --git a/packages/rs-dpp/src/balances/total_single_token_balance/mod.rs b/packages/rs-dpp/src/balances/total_single_token_balance/mod.rs new file mode 100644 index 0000000000..e7b0eb0c8c --- /dev/null +++ b/packages/rs-dpp/src/balances/total_single_token_balance/mod.rs @@ -0,0 +1,49 @@ +use crate::balances::credits::SignedTokenAmount; +use crate::ProtocolError; +use std::fmt; + +/// A structure where the token supply and the aggregated token account balances should always be equal +#[derive(Copy, Clone, Debug)] +pub struct TotalSingleTokenBalance { + /// the token supply + pub token_supply: SignedTokenAmount, + /// the sum of all user account balances + pub aggregated_token_account_balances: SignedTokenAmount, +} + +impl fmt::Display for TotalSingleTokenBalance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "TotalSingleTokenBalance {{")?; + writeln!(f, " token_supply: {},", self.token_supply)?; + writeln!( + f, + " aggregated_token_account_balances: {}", + self.aggregated_token_account_balances + )?; + write!(f, "}}") + } +} +impl TotalSingleTokenBalance { + /// Is the outcome okay? basically do the values match up + /// Errors in case of overflow + pub fn ok(&self) -> Result { + let TotalSingleTokenBalance { + token_supply, + aggregated_token_account_balances, + } = *self; + + if token_supply < 0 { + return Err(ProtocolError::Generic( + "Token in platform are less than 0".to_string(), + )); + } + + if aggregated_token_account_balances < 0 { + return Err(ProtocolError::Generic( + "Token in aggregated identity balances are less than 0".to_string(), + )); + } + + Ok(token_supply == aggregated_token_account_balances) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs index 072d8dfc7e..b4538389f2 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/tokens/validate_token_aggregated_balance/v0/mod.rs @@ -16,7 +16,7 @@ impl Platform { // Verify sum trees let token_balance = self .drive - .calculate_total_tokens_balance(Some(transaction), &platform_version.drive) + .calculate_total_tokens_balance(Some(transaction), platform_version) .map_err(Error::Drive)?; if !token_balance.ok()? { diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 9ce866c7cf..7ac860eac1 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -22,7 +22,8 @@ use dapi_grpc::platform::v0::{ GetDocumentsRequest, GetDocumentsResponse, GetEpochsInfoRequest, GetEpochsInfoResponse, GetEvonodesProposedEpochBlocksByIdsRequest, GetEvonodesProposedEpochBlocksByRangeRequest, GetEvonodesProposedEpochBlocksResponse, GetGroupInfoRequest, GetGroupInfoResponse, - GetIdentitiesBalancesRequest, GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, + GetGroupInfosRequest, GetGroupInfosResponse, GetIdentitiesBalancesRequest, + GetIdentitiesBalancesResponse, GetIdentitiesContractKeysRequest, GetIdentitiesContractKeysResponse, GetIdentitiesTokenBalancesRequest, GetIdentitiesTokenBalancesResponse, GetIdentitiesTokenInfosRequest, GetIdentitiesTokenInfosResponse, GetIdentityBalanceAndRevisionRequest, @@ -37,8 +38,8 @@ use dapi_grpc::platform::v0::{ GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, GetStatusRequest, GetStatusResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, - GetTotalCreditsInPlatformRequest, GetTotalCreditsInPlatformResponse, - GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, + GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, + GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, }; use dapi_grpc::tonic::{Code, Request, Response, Status}; @@ -675,6 +676,18 @@ impl PlatformService for QueryService { .await } + async fn get_token_total_supply( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_token_total_supply, + "get_token_total_supply", + ) + .await + } + async fn get_group_info( &self, request: Request, @@ -687,6 +700,18 @@ impl PlatformService for QueryService { .await } + async fn get_group_infos( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_group_infos, + "get_group_infos", + ) + .await + } + // async fn get_active_group_actions( // &self, // request: Request, diff --git a/packages/rs-drive-abci/src/query/token_queries/mod.rs b/packages/rs-drive-abci/src/query/token_queries/mod.rs index 70f261b383..fe97942dd1 100644 --- a/packages/rs-drive-abci/src/query/token_queries/mod.rs +++ b/packages/rs-drive-abci/src/query/token_queries/mod.rs @@ -3,3 +3,4 @@ mod identities_token_infos; mod identity_token_balances; mod identity_token_infos; mod token_status; +mod token_total_supply; diff --git a/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs b/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs index 555fce502d..ba68930d0d 100644 --- a/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs +++ b/packages/rs-drive-abci/src/query/token_queries/token_status/mod.rs @@ -20,7 +20,7 @@ impl Platform { let Some(version) = version else { return Ok(QueryValidationResult::new_with_error( QueryError::DecodingError( - "could not decode identity token infos query".to_string(), + "could not decode identity token statuses query".to_string(), ), )); }; diff --git a/packages/rs-drive-abci/src/query/token_queries/token_total_supply/mod.rs b/packages/rs-drive-abci/src/query/token_queries/token_total_supply/mod.rs new file mode 100644 index 0000000000..2100f9bfe7 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/token_total_supply/mod.rs @@ -0,0 +1,59 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_token_total_supply_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_token_total_supply_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of token total supply + pub fn query_token_total_supply( + &self, + GetTokenTotalSupplyRequest { version }: GetTokenTotalSupplyRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode identity token total supply query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .token_queries + .token_total_supply; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "token_total_supply".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = + self.query_token_total_supply_v0(request_v0, platform_state, platform_version)?; + Ok(result.map(|response_v0| GetTokenTotalSupplyResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/token_queries/token_total_supply/v0/mod.rs b/packages/rs-drive-abci/src/query/token_queries/token_total_supply/v0/mod.rs new file mode 100644 index 0000000000..d24a553308 --- /dev/null +++ b/packages/rs-drive-abci/src/query/token_queries/token_total_supply/v0/mod.rs @@ -0,0 +1,81 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_token_total_supply_request::GetTokenTotalSupplyRequestV0; +use dapi_grpc::platform::v0::get_token_total_supply_response::get_token_total_supply_response_v0::TokenTotalSupplyEntry; +use dapi_grpc::platform::v0::get_token_total_supply_response::{ + get_token_total_supply_response_v0, GetTokenTotalSupplyResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::identifier::Identifier; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_token_total_supply_v0( + &self, + GetTokenTotalSupplyRequestV0 { token_id, prove }: GetTokenTotalSupplyRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let token_id: [u8; 32] = + check_validation_result_with_data!(token_id.try_into().map_err(|_| { + QueryError::InvalidArgument( + "token_id must be a valid identifier (32 bytes long)".to_string(), + ) + })); + + let response = if prove { + let proof = check_validation_result_with_data!(self + .drive + .prove_token_total_supply_and_aggregated_identity_balances( + token_id, + None, + platform_version, + )); + + GetTokenTotalSupplyResponseV0 { + result: Some(get_token_total_supply_response_v0::Result::Proof( + self.response_proof_v0(platform_state, proof), + )), + metadata: Some(self.response_metadata_v0(platform_state)), + } + } else { + let Some(token_total_aggregated_identity_balances) = self + .drive + .fetch_token_total_aggregated_identity_balances(token_id, None, platform_version)? + else { + return Ok(QueryValidationResult::new_with_error(QueryError::NotFound( + format!("Token {} not found", Identifier::new(token_id)), + ))); + }; + + let Some(token_total_supply) = + self.drive + .fetch_token_total_supply(token_id, None, platform_version)? + else { + return Ok(QueryValidationResult::new_with_error(QueryError::NotFound( + format!("Token {} total supply not found", Identifier::new(token_id)), + ))); + }; + + GetTokenTotalSupplyResponseV0 { + result: Some( + get_token_total_supply_response_v0::Result::TokenTotalSupply( + TokenTotalSupplyEntry { + token_id: token_id.to_vec(), + total_aggregated_amount_in_user_accounts: + token_total_aggregated_identity_balances, + total_system_amount: token_total_supply, + }, + ), + ), + metadata: Some(self.response_metadata_v0(platform_state)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 9b140c4e55..be5ae7dedb 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= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } +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" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs index aff3c4d5fc..7dd930ddc6 100644 --- a/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs +++ b/packages/rs-drive/src/drive/shared/shared_estimation_costs/add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded/v0/mod.rs @@ -82,7 +82,7 @@ impl Drive { KeyInfoPath::from_known_path(vote_contested_resource_tree_path()), EstimatedLayerInformation { tree_type: TreeType::NormalTree, - // active poll "p", with "e" and "i" first so it should be on the second layer of the merk + // active poll "p", with "e" and "i" first, so it should be on the second layer of the merk estimated_layer_count: EstimatedLevel(1, false), estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), }, diff --git a/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs index 8084608b81..5d5692630b 100644 --- a/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/balance/fetch_identity_token_balances/v0/mod.rs @@ -1,4 +1,3 @@ -use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_BALANCES_KEY}; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; @@ -6,7 +5,7 @@ use crate::fees::op::LowLevelDriveOperation; use dpp::balances::credits::TokenAmount; use dpp::version::PlatformVersion; use grovedb::Element::SumItem; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::TransactionArg; use std::collections::BTreeMap; impl Drive { @@ -34,20 +33,7 @@ impl Drive { drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result>, Error> { - let tokens_root = tokens_root_path_vec(); - - let mut query = Query::new(); - - for token_id in token_ids { - query.insert_key(token_id.to_vec()); - } - - query.set_subquery_path(vec![vec![TOKEN_BALANCES_KEY], identity_id.to_vec()]); - - let path_query = PathQuery::new( - tokens_root, - SizedQuery::new(query, Some(token_ids.len() as u16), None), - ); + let path_query = Drive::token_balances_for_identity_id_query(token_ids, identity_id); self.grove_get_raw_path_query_with_optional( &path_query, @@ -59,9 +45,9 @@ impl Drive { .into_iter() .map(|(path, _, element)| { let token_id: [u8; 32] = path - .get(1) + .get(2) .ok_or(Error::Drive(DriveError::CorruptedDriveState( - "returned path item should always have a second part at index 1".to_string(), + "returned path item should always have a third part at index 2".to_string(), )))? .clone() .try_into() diff --git a/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs index 621e42c370..fad0b5357b 100644 --- a/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/balance/prove_identity_token_balances/v0/mod.rs @@ -1,9 +1,8 @@ -use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_BALANCES_KEY}; use crate::drive::Drive; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::version::PlatformVersion; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::TransactionArg; impl Drive { pub(super) fn prove_identity_token_balances_v0( @@ -30,20 +29,7 @@ impl Drive { drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result, Error> { - let tokens_root = tokens_root_path_vec(); - - let mut query = Query::new(); - - for token_id in token_ids { - query.insert_key(token_id.to_vec()); - } - - query.set_subquery_path(vec![vec![TOKEN_BALANCES_KEY], identity_id.to_vec()]); - - let path_query = PathQuery::new( - tokens_root, - SizedQuery::new(query, Some(token_ids.len() as u16), None), - ); + let path_query = Self::token_balances_for_identity_id_query(token_ids, identity_id); self.grove_get_proved_path_query( &path_query, @@ -53,3 +39,344 @@ impl Drive { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::balances::credits::TokenAmount; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::v1::DataContractV1; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::prelude::DataContract; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_multiple_token_balances_for_single_identity() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([ + ( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ( + 1, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ]), + }); + + let token_id_1 = contract.token_id(0).expect("expected token at position 0"); + let token_id_2 = contract.token_id(1).expect("expected token at position 1"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + drive + .token_mint( + token_id_1.to_buffer(), + identity.id().to_buffer(), + 5000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token 1"); + + let token_balance_1 = drive + .fetch_identity_token_balance( + token_id_1.to_buffer(), + identity_id, + None, + platform_version, + ) + .expect("should not error when fetching token balance"); + + assert_eq!(token_balance_1, Some(5000)); + + drive + .token_mint( + token_id_2.to_buffer(), + identity.id().to_buffer(), + 10000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint token 2"); + + let token_balance_2 = drive + .fetch_identity_token_balance( + token_id_2.to_buffer(), + identity_id, + None, + platform_version, + ) + .expect("should not error when fetching token balance"); + + assert_eq!(token_balance_2, Some(10000)); + + let token_balances = drive + .fetch_identity_token_balances( + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + identity_id, + None, + platform_version, + ) + .expect("should not error when fetching token balances"); + + assert_eq!( + token_balances, + BTreeMap::from([ + (token_id_1.to_buffer(), Some(5000)), + (token_id_2.to_buffer(), Some(10000)), + ]) + ); + + let proof = drive + .prove_identity_token_balances_v0( + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + identity_id, + None, + platform_version, + ) + .expect("should not error when proving token balances"); + + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_id( + proof.as_slice(), + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + identity.id().to_buffer(), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + assert_eq!( + proved_identity_balance, + BTreeMap::from([ + (token_id_1.to_buffer(), Some(5000)), + (token_id_2.to_buffer(), Some(10000)), + ]) + ); + } + + #[test] + fn should_prove_no_token_balances_for_single_identity() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let token_id = contract.token_id(0).expect("expected token at position 0"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + let proof = drive + .prove_identity_token_balances_v0( + &[token_id.to_buffer()], + identity_id, + None, + platform_version, + ) + .expect("should not error when proving token balances"); + + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_id( + proof.as_slice(), + &[token_id.to_buffer()], + identity.id().to_buffer(), + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + assert_eq!( + proved_identity_balance, + BTreeMap::from([(token_id.to_buffer(), None)]) + ); + } + + #[test] + fn should_prove_no_token_balances_for_non_existent_identity() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + // Create a random identity ID that is not added to the drive + let non_existent_identity_id = [1u8; 32]; // An example of a non-existent identity ID + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let token_id = contract.token_id(0).expect("expected token at position 0"); + + // Insert the contract but no identities + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Attempt to prove token balances for a non-existent identity + let proof_result = drive.prove_identity_token_balances_v0( + &[token_id.to_buffer()], + non_existent_identity_id, + None, + platform_version, + ); + + // Ensure proof generation succeeds even for non-existent identities + assert!(proof_result.is_ok(), "proof generation should succeed"); + + let proof = proof_result.expect("expected valid proof"); + + // Verify the proof + let proved_identity_balance: BTreeMap<[u8; 32], Option> = + Drive::verify_token_balances_for_identity_id( + proof.as_slice(), + &[token_id.to_buffer()], + non_existent_identity_id, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Verify the balance is `None` for the non-existent identity + assert_eq!( + proved_identity_balance, + BTreeMap::from([(token_id.to_buffer(), None)]), + "expected no balances for non-existent identity" + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/balance/queries.rs b/packages/rs-drive/src/drive/tokens/balance/queries.rs index d15202311a..a02a3216db 100644 --- a/packages/rs-drive/src/drive/tokens/balance/queries.rs +++ b/packages/rs-drive/src/drive/tokens/balance/queries.rs @@ -1,7 +1,12 @@ -use crate::drive::tokens::paths::token_balances_path_vec; +use crate::drive::balances::total_tokens_root_supply_path_vec; +use crate::drive::tokens::paths::{ + token_balances_path_vec, token_balances_root_path_vec, tokens_root_path_vec, TOKEN_BALANCES_KEY, +}; use crate::drive::Drive; +use crate::error::Error; use crate::query::{Query, QueryItem}; use grovedb::{PathQuery, SizedQuery}; +use platform_version::version::PlatformVersion; use std::ops::RangeFull; impl Drive { @@ -32,6 +37,27 @@ impl Drive { } } + /// The query getting token balances for a single identity and many tokens + pub fn token_balances_for_identity_id_query( + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + ) -> PathQuery { + let tokens_root = token_balances_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![identity_id.to_vec()]); + + PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ) + } + /// The query getting token balances for identities in a range pub fn token_balances_for_range_query( token_id: [u8; 32], @@ -69,4 +95,26 @@ impl Drive { }, } } + + /// The query getting token balances for identities in a range + pub fn token_total_supply_and_aggregated_identity_balances_query( + token_id: [u8; 32], + platform_version: &PlatformVersion, + ) -> Result { + let path_holding_total_token_supply = total_tokens_root_supply_path_vec(); + let token_supply_query = + PathQuery::new_single_key(path_holding_total_token_supply, token_id.to_vec()); + let tokens_root_path = token_balances_root_path_vec(); + let token_aggregated_identity_balances_query = + PathQuery::new_single_key(tokens_root_path, token_id.to_vec()); + let mut path_query = PathQuery::merge( + vec![ + &token_aggregated_identity_balances_query, + &token_supply_query, + ], + &platform_version.drive.grove_version, + )?; + path_query.query.limit = Some(2); + Ok(path_query) + } } diff --git a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs index 8799421a9d..60b85c9dbb 100644 --- a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs +++ b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/mod.rs @@ -6,6 +6,7 @@ use crate::error::Error; use dpp::balances::total_tokens_balance::TotalTokensBalance; use dpp::version::drive_versions::DriveVersion; use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; impl Drive { /// Calculates the total credits balance. @@ -28,10 +29,15 @@ impl Drive { pub fn calculate_total_tokens_balance( &self, transaction: TransactionArg, - drive_version: &DriveVersion, + platform_version: &PlatformVersion, ) -> Result { - match drive_version.methods.token.calculate_total_tokens_balance { - 0 => self.calculate_total_tokens_balance_v0(transaction, drive_version), + match platform_version + .drive + .methods + .token + .calculate_total_tokens_balance + { + 0 => self.calculate_total_tokens_balance_v0(transaction, platform_version), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "calculate_total_tokens_balance".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs index 6cefd4ce28..6d4acc6169 100644 --- a/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/calculate_total_tokens_balance/v0/mod.rs @@ -5,8 +5,8 @@ use crate::drive::Drive; use crate::error::Error; use crate::util::grove_operations::DirectQueryType; use dpp::balances::total_tokens_balance::TotalTokensBalance; -use dpp::version::drive_versions::DriveVersion; use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; impl Drive { /// Verify that the sum tree identity credits + pool credits + refunds are equal to the @@ -15,7 +15,7 @@ impl Drive { pub(super) fn calculate_total_tokens_balance_v0( &self, transaction: TransactionArg, - drive_version: &DriveVersion, + platform_version: &PlatformVersion, ) -> Result { let mut drive_operations = vec![]; let path_holding_total_credits = misc_path(); @@ -25,7 +25,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery, transaction, &mut drive_operations, - drive_version, + &platform_version.drive, )?; let tokens_root_path = tokens_root_path(); @@ -36,7 +36,7 @@ impl Drive { DirectQueryType::StatefulDirectQuery, transaction, &mut drive_operations, - drive_version, + &platform_version.drive, )?; Ok(TotalTokensBalance { diff --git a/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs index 6779f88038..21ab3474ba 100644 --- a/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/info/fetch_identity_token_infos/v0/mod.rs @@ -1,4 +1,3 @@ -use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_IDENTITY_INFO_KEY}; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; @@ -7,7 +6,7 @@ use dpp::serialization::PlatformDeserializable; use dpp::tokens::info::IdentityTokenInfo; use dpp::version::PlatformVersion; use grovedb::Element::Item; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::TransactionArg; use std::collections::BTreeMap; impl Drive { @@ -35,20 +34,7 @@ impl Drive { drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result>, Error> { - let tokens_root = tokens_root_path_vec(); - - let mut query = Query::new(); - - for token_id in token_ids { - query.insert_key(token_id.to_vec()); - } - - query.set_subquery_path(vec![vec![TOKEN_IDENTITY_INFO_KEY], identity_id.to_vec()]); - - let path_query = PathQuery::new( - tokens_root, - SizedQuery::new(query, Some(token_ids.len() as u16), None), - ); + let path_query = Drive::token_infos_for_identity_id_query(token_ids, identity_id); self.grove_get_raw_path_query_with_optional( &path_query, @@ -60,9 +46,9 @@ impl Drive { .into_iter() .map(|(path, _, element)| { let token_id: [u8; 32] = path - .get(1) + .get(2) .ok_or(Error::Drive(DriveError::CorruptedDriveState( - "returned path item should always have a second part at index 1".to_string(), + "returned path item should always have a third part at index 2".to_string(), )))? .clone() .try_into() diff --git a/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs b/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs index a0e4e71ac9..e6d7247d86 100644 --- a/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/info/prove_identity_token_infos/v0/mod.rs @@ -1,9 +1,8 @@ -use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_IDENTITY_INFO_KEY}; use crate::drive::Drive; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::version::PlatformVersion; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::TransactionArg; impl Drive { pub(super) fn prove_identity_token_infos_v0( @@ -30,20 +29,7 @@ impl Drive { drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result, Error> { - let tokens_root = tokens_root_path_vec(); - - let mut query = Query::new(); - - for token_id in token_ids { - query.insert_key(token_id.to_vec()); - } - - query.set_subquery_path(vec![vec![TOKEN_IDENTITY_INFO_KEY], identity_id.to_vec()]); - - let path_query = PathQuery::new( - tokens_root, - SizedQuery::new(query, Some(token_ids.len() as u16), None), - ); + let path_query = Self::token_infos_for_identity_id_query(token_ids, identity_id); self.grove_get_proved_path_query( &path_query, @@ -53,3 +39,247 @@ impl Drive { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::v1::DataContractV1; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::Identity; + use dpp::prelude::DataContract; + use dpp::tokens::info::v0::IdentityTokenInfoV0; + use dpp::tokens::info::IdentityTokenInfo; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_token_infos_with_one_token_frozen() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + // Create a random identity + let identity = Identity::random_identity(3, Some(14), platform_version) + .expect("expected a platform identity"); + + let identity_id = identity.id().to_buffer(); + + // Create a data contract with multiple tokens + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([ + ( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ( + 1, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ]), + }); + + let token_id_1 = contract.token_id(0).expect("expected token at position 0"); + let token_id_2 = contract.token_id(1).expect("expected token at position 1"); + + drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to add an identity"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Freeze one token for the identity + drive + .token_freeze( + token_id_1, + identity.id(), + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to freeze token"); + + let fetched_token_info_1 = drive + .fetch_identity_token_info(token_id_1.to_buffer(), identity_id, None, platform_version) + .expect("expected to fetch token info"); + + assert_eq!( + fetched_token_info_1, + Some(IdentityTokenInfo::V0(IdentityTokenInfoV0 { frozen: true })) + ); + + let fetched_token_info_2 = drive + .fetch_identity_token_info(token_id_2.to_buffer(), identity_id, None, platform_version) + .expect("expected to fetch token info"); + + assert_eq!(fetched_token_info_2, None); + + // Fetch identity token infos before proving + let fetched_token_infos = drive + .fetch_identity_token_infos( + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + identity_id, + None, + platform_version, + ) + .expect("expected to fetch token infos"); + + // Verify fetched token infos + assert_eq!( + fetched_token_infos, + BTreeMap::from([ + ( + token_id_1.to_buffer(), + Some(IdentityTokenInfo::V0(IdentityTokenInfoV0 { frozen: true })), + ), + (token_id_2.to_buffer(), None,), + ]), + "unexpected fetched token infos" + ); + + // Generate proof + let proof = drive + .prove_identity_token_infos_v0( + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + identity_id, + None, + platform_version, + ) + .expect("should not error when proving token infos"); + + // Verify proof + let proved_token_infos: BTreeMap<[u8; 32], Option> = + Drive::verify_token_infos_for_identity_id( + proof.as_slice(), + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + identity_id, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert proved token infos match the fetched ones + assert_eq!( + proved_token_infos, + BTreeMap::from([ + ( + token_id_1.to_buffer(), + Some(IdentityTokenInfo::V0(IdentityTokenInfoV0 { frozen: true })), + ), + (token_id_2.to_buffer(), None,), + ]), + "unexpected fetched token infos" + ); + } + + #[test] + fn should_prove_no_token_infos_for_non_existent_identity() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let non_existent_identity_id = [0u8; 32]; // An identity that doesn't exist in the database + + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let token_id = contract.token_id(0).expect("expected token at position 0"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + let proof = drive + .prove_identity_token_infos_v0( + &[token_id.to_buffer()], + non_existent_identity_id, + None, + platform_version, + ) + .expect("should not error when proving token infos for non-existent identity"); + + let proved_token_infos: BTreeMap<[u8; 32], Option> = + Drive::verify_token_infos_for_identity_id( + proof.as_slice(), + &[token_id.to_buffer()], + non_existent_identity_id, + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert that no token infos exist for the non-existent identity + assert_eq!( + proved_token_infos, + BTreeMap::from([(token_id.to_buffer(), None)]) + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/info/queries.rs b/packages/rs-drive/src/drive/tokens/info/queries.rs index 3b2303932d..c4e80a5af1 100644 --- a/packages/rs-drive/src/drive/tokens/info/queries.rs +++ b/packages/rs-drive/src/drive/tokens/info/queries.rs @@ -1,4 +1,7 @@ -use crate::drive::tokens::paths::token_identity_infos_path_vec; +use crate::drive::tokens::paths::{ + token_identity_infos_path_vec, token_identity_infos_root_path_vec, + token_statuses_root_path_vec, tokens_root_path_vec, TOKEN_STATUS_INFO_KEY, +}; use crate::drive::Drive; use crate::query::{Query, QueryItem}; use grovedb::{PathQuery, SizedQuery}; @@ -32,6 +35,43 @@ impl Drive { } } + /// The query getting a token infos for one identity + pub fn token_infos_for_identity_id_query( + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + ) -> PathQuery { + let tokens_root = token_identity_infos_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + query.set_subquery_path(vec![identity_id.to_vec()]); + + PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ) + } + + /// The query getting a token statuses + pub fn token_statuses_query(token_ids: &[[u8; 32]]) -> PathQuery { + let tokens_root = token_statuses_root_path_vec(); + + let mut query = Query::new(); + + for token_id in token_ids { + query.insert_key(token_id.to_vec()); + } + + PathQuery::new( + tokens_root, + SizedQuery::new(query, Some(token_ids.len() as u16), None), + ) + } + /// The query getting token infos for identities in a range pub fn token_infos_for_range_query( token_id: [u8; 32], diff --git a/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs b/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs index 486ebde128..8a9e1f23c3 100644 --- a/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/status/fetch_token_statuses/v0/mod.rs @@ -1,4 +1,3 @@ -use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_STATUS_INFO_KEY}; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; @@ -7,7 +6,7 @@ use dpp::serialization::PlatformDeserializable; use dpp::tokens::status::TokenStatus; use dpp::version::PlatformVersion; use grovedb::Element::Item; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::TransactionArg; use std::collections::BTreeMap; impl Drive { @@ -32,20 +31,7 @@ impl Drive { drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result>, Error> { - let tokens_root = tokens_root_path_vec(); - - let mut query = Query::new(); - - for token_id in token_ids { - query.insert_key(token_id.to_vec()); - } - - query.set_subquery_path(vec![vec![TOKEN_STATUS_INFO_KEY]]); - - let path_query = PathQuery::new( - tokens_root, - SizedQuery::new(query, Some(token_ids.len() as u16), None), - ); + let path_query = Drive::token_statuses_query(token_ids); self.grove_get_raw_path_query_with_optional( &path_query, diff --git a/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs b/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs index baae7936be..07b6fef19c 100644 --- a/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs +++ b/packages/rs-drive/src/drive/tokens/status/prove_token_statuses/v0/mod.rs @@ -1,9 +1,8 @@ -use crate::drive::tokens::paths::{tokens_root_path_vec, TOKEN_IDENTITY_INFO_KEY}; use crate::drive::Drive; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use dpp::version::PlatformVersion; -use grovedb::{PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb::TransactionArg; impl Drive { pub(super) fn prove_token_statuses_v0( @@ -27,20 +26,7 @@ impl Drive { drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result, Error> { - let tokens_root = tokens_root_path_vec(); - - let mut query = Query::new(); - - for token_id in token_ids { - query.insert_key(token_id.to_vec()); - } - - query.set_subquery_path(vec![vec![TOKEN_IDENTITY_INFO_KEY]]); - - let path_query = PathQuery::new( - tokens_root, - SizedQuery::new(query, Some(token_ids.len() as u16), None), - ); + let path_query = Self::token_statuses_query(token_ids); self.grove_get_proved_path_query( &path_query, @@ -50,3 +36,186 @@ impl Drive { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::v1::DataContractV1; + use dpp::prelude::DataContract; + use dpp::tokens::status::v0::TokenStatusV0; + use dpp::tokens::status::TokenStatus; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_token_statuses_for_multiple_tokens() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + // Create a data contract with multiple tokens + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([ + ( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ( + 1, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + ), + ]), + }); + + let token_id_1 = contract.token_id(0).expect("expected token at position 0"); + let token_id_2 = contract.token_id(1).expect("expected token at position 1"); + + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Freeze the first token + drive + .token_apply_status( + token_id_1.to_buffer(), + TokenStatus::new(true, platform_version).expect("expected token status"), + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to freeze token"); + + let fetched_token_info_1 = drive + .fetch_token_status(token_id_1.to_buffer(), None, platform_version) + .expect("expected to fetch token status"); + + assert_eq!( + fetched_token_info_1, + Some(TokenStatus::V0(TokenStatusV0 { paused: true })) + ); + + let fetched_token_info_2 = drive + .fetch_token_status(token_id_2.to_buffer(), None, platform_version) + .expect("expected to fetch token status"); + + assert_eq!(fetched_token_info_2, None); + + // Fetch token statuses before proving + let fetched_token_statuses = drive + .fetch_token_statuses( + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + None, + platform_version, + ) + .expect("expected to fetch token statuses"); + + // Verify fetched token statuses + assert_eq!( + fetched_token_statuses, + BTreeMap::from([ + ( + token_id_1.to_buffer(), + Some(TokenStatus::V0(TokenStatusV0 { paused: true })), + ), + (token_id_2.to_buffer(), None,), + ]), + "unexpected fetched token infos" + ); + + // Generate proof + let proof = drive + .prove_token_statuses( + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + None, + platform_version, + ) + .expect("should not error when proving token statuses"); + + // Verify proof + let proved_token_statuses: BTreeMap<[u8; 32], Option> = + Drive::verify_token_statuses( + proof.as_slice(), + &[token_id_1.to_buffer(), token_id_2.to_buffer()], + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert the token statuses match expected values + assert_eq!( + proved_token_statuses, + BTreeMap::from([ + ( + token_id_1.to_buffer(), + Some(TokenStatus::V0(TokenStatusV0 { paused: true })) + ), + (token_id_2.to_buffer(), None), + ]), + "unexpected token statuses" + ); + } + + #[test] + fn should_prove_no_token_statuses_for_non_existent_tokens() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let non_existent_token_id = [0u8; 32]; // A token ID that doesn't exist in the database + + // Generate proof + let proof = drive + .prove_token_statuses_v0(&[non_existent_token_id], None, platform_version) + .expect("should not error when proving token statuses for non-existent tokens"); + + // Verify proof + let proved_token_statuses: BTreeMap<[u8; 32], Option> = + Drive::verify_token_statuses( + proof.as_slice(), + &[non_existent_token_id], + false, + platform_version, + ) + .expect("expected proof verification to succeed") + .1; + + // Assert that the token status is `None` for the non-existent token + assert_eq!( + proved_token_statuses, + BTreeMap::from([(non_existent_token_id, None)]), + "unexpected token statuses for non-existent tokens" + ); + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/mod.rs b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/mod.rs new file mode 100644 index 0000000000..aac5a63ff6 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/mod.rs @@ -0,0 +1,74 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Fetches token's total aggregated_identity_balances + pub fn fetch_token_total_aggregated_identity_balances( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .token_total_aggregated_identity_balances + { + 0 => self.fetch_token_total_aggregated_identity_balances_v0( + token_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_total_aggregated_identity_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations of fetching the token total aggregated_identity_balances + pub fn fetch_token_total_aggregated_identity_balances_add_to_operations( + &self, + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .token_total_aggregated_identity_balances + { + 0 => self.fetch_token_total_aggregated_identity_balances_add_to_operations_v0( + token_id, + estimated_costs_only_with_layer_info, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_total_aggregated_identity_balances_add_to_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/v0/mod.rs new file mode 100644 index 0000000000..035091d052 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_aggregated_identity_balances/v0/mod.rs @@ -0,0 +1,75 @@ +use crate::drive::tokens::paths::token_balances_root_path; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn fetch_token_total_aggregated_identity_balances_v0( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + self.fetch_token_total_aggregated_identity_balances_add_to_operations_v0( + token_id, + &mut None, + transaction, + &mut drive_operations, + platform_version, + ) + } + + pub(super) fn fetch_token_total_aggregated_identity_balances_add_to_operations_v0( + &self, + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + // If we only estimate, add estimation costs + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + // Add your estimation logic similar to add_to_system_credits_operations_v0 + // For example: + Self::add_estimation_costs_for_token_balances( + token_id, + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::BigSumTree, + query_target: QueryTargetValue(8), + } + }; + + let tokens_root_path = token_balances_root_path(); + + let total_token_aggregated_identity_balances_in_platform = self + .grove_get_raw_value_u64_from_encoded_var_vec( + (&tokens_root_path).into(), + &token_id, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )?; + + Ok(total_token_aggregated_identity_balances_in_platform) + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/mod.rs b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/mod.rs new file mode 100644 index 0000000000..fac0478a0e --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/mod.rs @@ -0,0 +1,69 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Fetches token's total supply + pub fn fetch_token_total_supply( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .token_total_supply + { + 0 => self.fetch_token_total_supply_v0(token_id, transaction, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_total_supply".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Adds the operations of fetching the token total supply + pub fn fetch_token_total_supply_add_to_operations( + &self, + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .fetch + .token_total_supply + { + 0 => self.fetch_token_total_supply_add_to_operations_v0( + token_id, + estimated_costs_only_with_layer_info, + transaction, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_token_total_supply_add_to_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/v0/mod.rs new file mode 100644 index 0000000000..2d92c49bf3 --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/fetch_token_total_supply/v0/mod.rs @@ -0,0 +1,72 @@ +use crate::drive::balances::total_tokens_root_supply_path; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg, TreeType}; +use std::collections::HashMap; + +impl Drive { + pub(super) fn fetch_token_total_supply_v0( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let mut drive_operations = vec![]; + + self.fetch_token_total_supply_add_to_operations_v0( + token_id, + &mut None, + transaction, + &mut drive_operations, + platform_version, + ) + } + + pub(super) fn fetch_token_total_supply_add_to_operations_v0( + &self, + token_id: [u8; 32], + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + // If we only estimate, add estimation costs + if let Some(estimated_costs_only_with_layer_info) = estimated_costs_only_with_layer_info { + // Add your estimation logic similar to add_to_system_credits_operations_v0 + // For example: + Self::add_estimation_costs_for_token_total_supply( + estimated_costs_only_with_layer_info, + &platform_version.drive, + )?; + } + + let direct_query_type = if estimated_costs_only_with_layer_info.is_none() { + DirectQueryType::StatefulDirectQuery + } else { + DirectQueryType::StatelessDirectQuery { + in_tree_type: TreeType::BigSumTree, + query_target: QueryTargetValue(8), + } + }; + + let path_holding_total_token_supply = total_tokens_root_supply_path(); + let total_token_supply_in_platform = self.grove_get_raw_value_u64_from_encoded_var_vec( + (&path_holding_total_token_supply).into(), + &token_id, + direct_query_type, + transaction, + drive_operations, + &platform_version.drive, + )?; + + Ok(total_token_supply_in_platform) + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/mod.rs b/packages/rs-drive/src/drive/tokens/system/mod.rs index 8d0f456d61..e9fcbd0c30 100644 --- a/packages/rs-drive/src/drive/tokens/system/mod.rs +++ b/packages/rs-drive/src/drive/tokens/system/mod.rs @@ -1,3 +1,6 @@ mod add_to_token_total_supply; mod create_token_trees; +mod fetch_token_total_aggregated_identity_balances; +mod fetch_token_total_supply; +mod prove_token_total_supply_and_aggregated_identity_balances; mod remove_from_token_total_supply; diff --git a/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs new file mode 100644 index 0000000000..26f2ad535f --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/mod.rs @@ -0,0 +1,40 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::balances::credits::TokenAmount; +use dpp::version::PlatformVersion; +use grovedb::batch::KeyInfoPath; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// Proves token's total supply and aggregated identity balances + pub fn prove_token_total_supply_and_aggregated_identity_balances( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .token + .prove + .total_supply_and_aggregated_identity_balances + { + 0 => self.prove_token_total_supply_and_aggregated_identity_balances_v0( + token_id, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_token_total_supply_and_aggregated_identity_balances".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs new file mode 100644 index 0000000000..7dde90d7ef --- /dev/null +++ b/packages/rs-drive/src/drive/tokens/system/prove_token_total_supply_and_aggregated_identity_balances/v0/mod.rs @@ -0,0 +1,257 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn prove_token_total_supply_and_aggregated_identity_balances_v0( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_token_total_supply_and_aggregated_identity_balances_add_operations_v0( + token_id, + transaction, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_token_total_supply_and_aggregated_identity_balances_add_operations_v0( + &self, + token_id: [u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let combined_path_query = Drive::token_total_supply_and_aggregated_identity_balances_query( + token_id, + platform_version, + )?; + self.grove_get_proved_path_query( + &combined_path_query, + transaction, + drive_operations, + &platform_version.drive, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::block::block_info::BlockInfo; + use dpp::data_contract::accessors::v1::DataContractV1Getters; + use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0; + use dpp::data_contract::associated_token::token_configuration::TokenConfiguration; + use dpp::data_contract::config::v0::DataContractConfigV0; + use dpp::data_contract::config::DataContractConfig; + use dpp::data_contract::v1::DataContractV1; + use dpp::prelude::DataContract; + use dpp::version::PlatformVersion; + use std::collections::BTreeMap; + + #[test] + fn should_prove_token_total_supply_and_aggregated_identity_balances() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + // Create a data contract with a token + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let token_id = contract.token_id(0).expect("expected token at position 0"); + + // Insert contract into Drive + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Mint tokens for identity accounts + let identity_1 = [1u8; 32]; + let identity_2 = [2u8; 32]; + + drive + .token_mint( + token_id.to_buffer(), + identity_1, + 50_000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint tokens for identity 1"); + + drive + .token_mint( + token_id.to_buffer(), + identity_2, + 50_000, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to mint tokens for identity 2"); + + // Prove token total supply and aggregated identity balances + let proof = drive + .prove_token_total_supply_and_aggregated_identity_balances( + token_id.to_buffer(), + None, + platform_version, + ) + .expect("should not error when proving total supply and balances"); + + // Verify proof + let (root_hash, total_single_token_balance) = + Drive::verify_token_total_supply_and_aggregated_identity_balance( + proof.as_slice(), + token_id.to_buffer(), + false, + platform_version, + ) + .expect("expected proof verification to succeed"); + + // Assert root hash is not empty + assert!(!root_hash.is_empty(), "expected a valid root hash"); + + // Assert total supply matches aggregated identity balances + // The contract was created with 100k, then 50k to each identity + assert_eq!( + total_single_token_balance.token_supply, 200_000, + "unexpected token supply" + ); + assert_eq!( + total_single_token_balance.aggregated_token_account_balances, 200_000, + "unexpected aggregated token account balances" + ); + + // Assert that the total balance is valid + assert!( + total_single_token_balance + .ok() + .expect("expected total balance to be valid"), + "unexpected total balance validation failure" + ); + } + + #[test] + fn should_prove_token_total_supply_and_aggregated_identity_balances_for_empty_token() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + // Create a data contract with a token + let contract = DataContract::V1(DataContractV1 { + id: Default::default(), + version: 0, + owner_id: Default::default(), + document_types: Default::default(), + metadata: None, + config: DataContractConfig::V0(DataContractConfigV0 { + can_be_deleted: false, + readonly: false, + keeps_history: false, + documents_keep_history_contract_default: false, + documents_mutable_contract_default: false, + documents_can_be_deleted_contract_default: false, + requires_identity_encryption_bounded_key: None, + requires_identity_decryption_bounded_key: None, + }), + schema_defs: None, + groups: Default::default(), + tokens: BTreeMap::from([( + 0, + TokenConfiguration::V0(TokenConfigurationV0::default_most_restrictive()), + )]), + }); + + let token_id = contract.token_id(0).expect("expected token at position 0"); + + // Insert contract into Drive + drive + .insert_contract( + &contract, + BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("expected to insert contract"); + + // Prove token total supply and aggregated identity balances for a token with no supply + let proof = drive + .prove_token_total_supply_and_aggregated_identity_balances_v0( + token_id.to_buffer(), + None, + platform_version, + ) + .expect("should not error when proving total supply and balances"); + + // Verify proof + let (root_hash, total_single_token_balance) = + Drive::verify_token_total_supply_and_aggregated_identity_balance( + proof.as_slice(), + token_id.to_buffer(), + false, + platform_version, + ) + .expect("expected proof verification to succeed"); + + // Assert root hash is not empty + assert!(!root_hash.is_empty(), "expected a valid root hash"); + + // Assert total supply matches aggregated identity balances + assert_eq!( + total_single_token_balance.token_supply, 0, + "unexpected token supply" + ); + assert_eq!( + total_single_token_balance.aggregated_token_account_balances, 0, + "unexpected aggregated token account balances" + ); + + // Assert that the total balance is valid + assert!( + total_single_token_balance + .ok() + .expect("expected total balance to be valid"), + "unexpected total balance validation failure" + ); + } +} diff --git a/packages/rs-drive/src/error/proof.rs b/packages/rs-drive/src/error/proof.rs index 504aa11f55..b2c14a57ed 100644 --- a/packages/rs-drive/src/error/proof.rs +++ b/packages/rs-drive/src/error/proof.rs @@ -30,6 +30,13 @@ pub enum ProofError { #[error("incorrect proof error: {0}")] IncorrectProof(String), + /// The proof returned is said to be valid, data is what we asked for, but is not what was + /// expected, for example we ask for token balance, and we get that the token does not exist. + /// UnexpectedResultProof is most likely is a User error. + /// IncorrectProof is most likely a system error. + #[error("unexpected result in proof error: {0}")] + UnexpectedResultProof(String), + /// The transition we are trying to prove was executed is invalid #[error("invalid transition error: {0}")] InvalidTransition(String), @@ -85,5 +92,6 @@ fn get_error_code(error: &ProofError) -> u32 { ProofError::ErrorRetrievingContract(_) => 6010, ProofError::InvalidMetadata(_) => 6011, ProofError::MissingContextRequirement(_) => 6012, + ProofError::UnexpectedResultProof(_) => 6013, } } diff --git a/packages/rs-drive/src/verify/tokens/mod.rs b/packages/rs-drive/src/verify/tokens/mod.rs index 9110a47eed..91e8d10e09 100644 --- a/packages/rs-drive/src/verify/tokens/mod.rs +++ b/packages/rs-drive/src/verify/tokens/mod.rs @@ -1,2 +1,6 @@ +mod verify_token_balances_for_identity_id; mod verify_token_balances_for_identity_ids; +mod verify_token_infos_for_identity_id; mod verify_token_infos_for_identity_ids; +mod verify_token_statuses; +mod verify_token_total_supply_and_aggregated_identity_balance; diff --git a/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/mod.rs new file mode 100644 index 0000000000..dd2c088859 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/mod.rs @@ -0,0 +1,75 @@ +mod v0; + +use crate::drive::Drive; +use dpp::balances::credits::TokenAmount; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the balances of tokens held by a specific identity using a cryptographic proof. + /// + /// This method checks the cryptographic proof to verify the balances of a list of tokens + /// associated with the given identity ID. It dispatches to version-specific implementations + /// based on the platform version. + /// + /// # Parameters + /// - `proof`: The cryptographic proof to verify. + /// - `token_ids`: A list of token IDs to verify (each a 32-byte array). + /// - `identity_id`: The unique identifier of the identity (32-byte array). + /// - `verify_subset_of_proof`: Whether to verify only a subset of the proof. + /// - `platform_version`: The current platform version. + /// + /// # Returns + /// - `Ok((RootHash, T))`: + /// - `RootHash`: The verified root hash of the database. + /// - `T`: A collection of `(token ID, token balance)` pairs. + /// + /// # Errors + /// - `Error::Drive(DriveError::UnknownVersionMismatch)`: + /// - Occurs when the platform version does not match any known version for this method. + /// - `Error::Proof(ProofError::WrongElementCount)`: + /// - If the number of elements in the proof does not match the number of token IDs. + /// - `Error::Proof(ProofError::IncorrectValueSize)`: + /// - If the token ID size or proof value size is invalid. + /// - `Error::Proof(ProofError::InvalidSumItemValue)`: + /// - If the proof element does not represent a valid sum item. + /// - `Error::Proof(ProofError::InvalidItemType)`: + /// - If the proof element is not a sum item as expected for balances. + pub fn verify_token_balances_for_identity_id< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .token + .verify_token_balances_for_identity_id + { + 0 => Self::verify_token_balances_for_identity_id_v0( + proof, + token_ids, + identity_id, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_token_balances_for_identity_id".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/v0/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/v0/mod.rs new file mode 100644 index 0000000000..a894346132 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_balances_for_identity_id/v0/mod.rs @@ -0,0 +1,72 @@ +use crate::drive::Drive; +use grovedb::Element::SumItem; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::balances::credits::TokenAmount; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_token_balances_for_identity_id_v0< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Self::token_balances_for_identity_id_query(token_ids, identity_id); + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + if proved_key_values.len() == token_ids.len() { + let values = proved_key_values + .into_iter() + .map(|proved_key_value| { + let token_id: [u8; 32] = proved_key_value + .0 + .get(2) + .ok_or(Error::Proof(ProofError::IncorrectValueSize( + "path should have at least 3 elements in returned proof", + )))? + .clone() + .try_into() + .map_err(|_| { + Error::Proof(ProofError::IncorrectValueSize("token id size")) + })?; + match proved_key_value.2 { + Some(SumItem(value, ..)) => { + Ok((token_id.into(), Some(value as TokenAmount))) + } + None => Ok((token_id.into(), None)), + _ => Err(Error::Proof(ProofError::IncorrectValueSize( + "proof did not point to a sum item", + ))), + } + }) + .collect::>()?; + Ok((root_hash, values)) + } else { + Err(Error::Proof(ProofError::WrongElementCount { + expected: token_ids.len(), + got: proved_key_values.len(), + })) + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/mod.rs new file mode 100644 index 0000000000..e0a39d6263 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/mod.rs @@ -0,0 +1,74 @@ +mod v0; + +use crate::drive::Drive; +use dpp::tokens::info::IdentityTokenInfo; + +use crate::error::drive::DriveError; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies token information for a specific identity using a cryptographic proof. + /// + /// This method retrieves information about the specified tokens for a given identity ID from the + /// cryptographic proof. It dispatches to version-specific implementations based on the platform version. + /// + /// # Parameters + /// - `proof`: The cryptographic proof to verify. + /// - `token_ids`: A list of token IDs to verify (each a 32-byte array). + /// - `identity_id`: The unique identifier of the identity (32-byte array). + /// - `verify_subset_of_proof`: Whether to verify only a subset of the proof. + /// - `platform_version`: The current platform version. + /// + /// # Returns + /// - `Ok((RootHash, T))`: + /// - `RootHash`: The verified root hash of the database. + /// - `T`: A collection of `(token ID, token info)` pairs. + /// + /// # Errors + /// - `Error::Drive(DriveError::UnknownVersionMismatch)`: + /// - Occurs when the platform version does not match any known version for this method. + /// - `Error::Proof(ProofError::WrongElementCount)`: + /// - If the number of elements in the proof does not match the number of token IDs. + /// - `Error::Proof(ProofError::IncorrectValueSize)`: + /// - If the token ID size or proof value size is invalid. + /// - `Error::Proof(ProofError::DeserializationFailed)`: + /// - If the token info cannot be deserialized from the proof. + /// - `Error::Proof(ProofError::InvalidItemType)`: + /// - If the proof element is not an expected item type (e.g., `Item`). + pub fn verify_token_infos_for_identity_id< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .token + .verify_token_infos_for_identity_id + { + 0 => Self::verify_token_infos_for_identity_id_v0( + proof, + token_ids, + identity_id, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_token_infos_for_identity_id".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/v0/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/v0/mod.rs new file mode 100644 index 0000000000..e94d164d31 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_infos_for_identity_id/v0/mod.rs @@ -0,0 +1,74 @@ +use crate::drive::Drive; +use grovedb::Element::Item; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::info::IdentityTokenInfo; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_token_infos_for_identity_id_v0< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_ids: &[[u8; 32]], + identity_id: [u8; 32], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Self::token_infos_for_identity_id_query(token_ids, identity_id); + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + if proved_key_values.len() == token_ids.len() { + let values = proved_key_values + .into_iter() + .map(|proved_key_value| { + let token_id: [u8; 32] = proved_key_value + .0 + .get(2) + .ok_or(Error::Proof(ProofError::IncorrectProof( + "path should have at least 3 elements in returned proof".to_string(), + )))? + .clone() + .try_into() + .map_err(|_| { + Error::Proof(ProofError::IncorrectValueSize("token id size")) + })?; + match proved_key_value.2 { + Some(Item(value, ..)) => Ok(( + token_id.into(), + Some(IdentityTokenInfo::deserialize_from_bytes(&value)?), + )), + None => Ok((token_id.into(), None)), + _ => Err(Error::Proof(ProofError::IncorrectProof( + "proof did not point to an item as expected for token info".to_string(), + ))), + } + }) + .collect::>()?; + Ok((root_hash, values)) + } else { + Err(Error::Proof(ProofError::WrongElementCount { + expected: token_ids.len(), + got: proved_key_values.len(), + })) + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs new file mode 100644 index 0000000000..7b7e9b8287 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_statuses/mod.rs @@ -0,0 +1,68 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use dpp::tokens::info::IdentityTokenInfo; +use dpp::tokens::status::TokenStatus; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the statuses of multiple tokens using a cryptographic proof. + /// + /// This method validates the cryptographic proof to retrieve the statuses of the specified token IDs. + /// It dispatches to version-specific implementations based on the provided platform version. + /// + /// # Parameters + /// - `proof`: The cryptographic proof to verify. + /// - `token_ids`: A list of token IDs to verify (each a 32-byte array). + /// - `verify_subset_of_proof`: Whether to verify only a subset of the proof. + /// - `platform_version`: The current platform version. + /// + /// # Returns + /// - `Ok((RootHash, T))`: + /// - `RootHash`: The verified root hash of the database. + /// - `T`: A collection of `(token ID, token status)` pairs. + /// + /// # Errors + /// - `Error::Drive(DriveError::UnknownVersionMismatch)`: + /// - Occurs when the platform version does not match any known version for this method. + /// - `Error::Proof(ProofError::WrongElementCount)`: + /// - If the number of elements in the proof does not match the number of token IDs. + /// - `Error::Proof(ProofError::IncorrectValueSize)`: + /// - If the token ID size or proof value size is invalid. + /// - `Error::Proof(ProofError::DeserializationFailed)`: + /// - If the token status cannot be deserialized from the proof. + /// - `Error::Proof(ProofError::InvalidItemType)`: + /// - If the proof element is not an expected item type (e.g., `Item`). + pub fn verify_token_statuses)>, I: From<[u8; 32]>>( + proof: &[u8], + token_ids: &[[u8; 32]], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + match platform_version + .drive + .methods + .verify + .token + .verify_token_statuses + { + 0 => Self::verify_token_statuses_v0( + proof, + token_ids, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_token_statuses".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_statuses/v0/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_statuses/v0/mod.rs new file mode 100644 index 0000000000..aa6ad189c0 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_statuses/v0/mod.rs @@ -0,0 +1,65 @@ +use crate::drive::Drive; +use grovedb::Element::Item; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::serialization::PlatformDeserializable; +use dpp::tokens::status::TokenStatus; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_token_statuses_v0< + T: FromIterator<(I, Option)>, + I: From<[u8; 32]>, + >( + proof: &[u8], + token_ids: &[[u8; 32]], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, T), Error> { + let path_query = Self::token_statuses_query(token_ids); + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + if proved_key_values.len() == token_ids.len() { + let values = proved_key_values + .into_iter() + .map(|proved_key_value| { + let token_id: [u8; 32] = proved_key_value.1.try_into().map_err(|_| { + Error::Proof(ProofError::IncorrectValueSize("token id size")) + })?; + match proved_key_value.2 { + Some(Item(value, ..)) => Ok(( + token_id.into(), + Some(TokenStatus::deserialize_from_bytes(&value)?), + )), + None => Ok((token_id.into(), None)), + _ => Err(Error::Proof(ProofError::IncorrectValueSize( + "proof did not point to an item as expected for token info", + ))), + } + }) + .collect::>()?; + Ok((root_hash, values)) + } else { + Err(Error::Proof(ProofError::WrongElementCount { + expected: token_ids.len(), + got: proved_key_values.len(), + })) + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs new file mode 100644 index 0000000000..1c2b950104 --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/mod.rs @@ -0,0 +1,69 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use dpp::balances::credits::TokenAmount; +use dpp::balances::total_single_token_balance::TotalSingleTokenBalance; +use dpp::balances::total_tokens_balance::TotalTokensBalance; + +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies the total token supply and aggregated identity balances for a given token. + /// + /// This method checks the cryptographic proof to verify the total supply of a token and the + /// aggregated balances of identities associated with that token. It dispatches to version-specific + /// implementations based on the provided platform version. + /// + /// # Parameters + /// - `proof`: The cryptographic proof to verify. + /// - `token_id`: The unique identifier of the token (32-byte array). + /// - `verify_subset_of_proof`: Whether to verify only a subset of the proof. + /// - `platform_version`: The current platform version. + /// + /// # Returns + /// - `Ok((RootHash, TotalSingleTokenBalance))`: + /// - `RootHash`: The verified root hash of the database. + /// - `TotalSingleTokenBalance`: The total supply and aggregated identity balances of the token. + /// + /// # Errors + /// - `Error::Drive(DriveError::UnknownVersionMismatch)`: + /// - Occurs when the platform version does not match any known version for this method. + /// - `Error::Proof(ProofError::UnexpectedResultProof)`: + /// - If the token does not exist in the proof. + /// - If the token's supply is not found in the proof. + /// - `Error::Proof(ProofError::WrongElementCount)`: + /// - If the proof does not contain exactly two expected elements (total supply and aggregated balances). + /// - `Error::Proof(ProofError::InvalidSumItemValue)`: + /// - If the retrieved proof element is not a valid sum item. + pub fn verify_token_total_supply_and_aggregated_identity_balance( + proof: &[u8], + token_id: [u8; 32], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, TotalSingleTokenBalance), Error> { + match platform_version + .drive + .methods + .verify + .token + .verify_token_total_supply_and_aggregated_identity_balance + { + 0 => Self::verify_token_total_supply_and_aggregated_identity_balance_v0( + proof, + token_id, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_token_total_supply_and_aggregated_identity_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/v0/mod.rs b/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/v0/mod.rs new file mode 100644 index 0000000000..5fd81f013f --- /dev/null +++ b/packages/rs-drive/src/verify/tokens/verify_token_total_supply_and_aggregated_identity_balance/v0/mod.rs @@ -0,0 +1,73 @@ +use crate::drive::Drive; + +use crate::error::proof::ProofError; +use crate::error::Error; + +use crate::verify::RootHash; + +use dpp::balances::total_single_token_balance::TotalSingleTokenBalance; +use dpp::prelude::Identifier; +use grovedb::GroveDb; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_token_total_supply_and_aggregated_identity_balance_v0( + proof: &[u8], + token_id: [u8; 32], + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, TotalSingleTokenBalance), Error> { + let path_query = Self::token_total_supply_and_aggregated_identity_balances_query( + token_id, + platform_version, + )?; + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; + if proved_key_values.len() == 2 { + let ( + _aggregated_identity_balances_path, + _aggregated_identity_balances_key, + Some(aggregated_identity_balances_element), + ) = proved_key_values.get(0).unwrap() + else { + return Err(Error::Proof(ProofError::UnexpectedResultProof(format!( + "Token {} most likely does not exist", + Identifier::new(token_id) + )))); + }; + let (_total_supply_path, _total_supply_key, Some(total_supply_element)) = + proved_key_values.get(1).unwrap() + else { + return Err(Error::Proof(ProofError::UnexpectedResultProof(format!( + "Token {} has no known supply", + Identifier::new(token_id) + )))); + }; + + Ok(( + root_hash, + TotalSingleTokenBalance { + token_supply: total_supply_element.as_sum_item_value()?, + aggregated_token_account_balances: aggregated_identity_balances_element + .as_sum_tree_value()?, + }, + )) + } else { + Err(Error::Proof(ProofError::WrongElementCount { + expected: 2, + got: proved_key_values.len(), + })) + } + } +} diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index e7e66db2df..f7b1c45da6 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= "d8ae2d95f56381b4d104d3983b2f11ae3a968dc7" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev= "e3ac3f7883bb0f2e25936153f76d447b42ebc9c0" } once_cell = "1.19.0" [features] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index 7faf75df46..bb2e8559b7 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -30,6 +30,7 @@ pub struct DriveAbciQueryTokenVersions { pub identities_token_infos: FeatureVersionBounds, pub identity_token_infos: FeatureVersionBounds, pub token_statuses: FeatureVersionBounds, + pub token_total_supply: FeatureVersionBounds, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index e4bb8e03fb..2db3bde39c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -99,6 +99,11 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV max_version: 0, default_current_version: 0, }, + token_total_supply: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }, validator_queries: DriveAbciQueryValidatorVersions { proposed_block_counts_by_evonode_ids: FeatureVersionBounds { diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs index e10ff81316..e7341f1f6f 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/mod.rs @@ -20,6 +20,8 @@ pub struct DriveTokenFetchMethodVersions { pub identities_token_infos: FeatureVersion, pub token_statuses: FeatureVersion, pub token_status: FeatureVersion, + pub token_total_supply: FeatureVersion, + pub token_total_aggregated_identity_balances: FeatureVersion, } #[derive(Clone, Debug, Default)] @@ -31,6 +33,7 @@ pub struct DriveTokenProveMethodVersions { pub identity_token_infos: FeatureVersion, pub identities_token_infos: FeatureVersion, pub token_statuses: FeatureVersion, + pub total_supply_and_aggregated_identity_balances: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs index 9b8f9d83ad..0d552a4313 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_token_method_versions/v1.rs @@ -13,6 +13,8 @@ pub const DRIVE_TOKEN_METHOD_VERSIONS_V1: DriveTokenMethodVersions = DriveTokenM identities_token_infos: 0, token_statuses: 0, token_status: 0, + token_total_supply: 0, + token_total_aggregated_identity_balances: 0, }, prove: DriveTokenProveMethodVersions { identity_token_balance: 0, @@ -22,6 +24,7 @@ pub const DRIVE_TOKEN_METHOD_VERSIONS_V1: DriveTokenMethodVersions = DriveTokenM identity_token_infos: 0, identities_token_infos: 0, token_statuses: 0, + total_supply_and_aggregated_identity_balances: 0, }, update: DriveTokenUpdateMethodVersions { create_token_trees: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index e23fd54276..5b2309458d 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -48,6 +48,9 @@ pub struct DriveVerifyTokenMethodVersions { pub verify_token_balances_for_identity_ids: FeatureVersion, pub verify_token_balances_for_identity_id: FeatureVersion, pub verify_token_infos_for_identity_ids: FeatureVersion, + pub verify_token_infos_for_identity_id: FeatureVersion, + pub verify_token_statuses: FeatureVersion, + pub verify_token_total_supply_and_aggregated_identity_balance: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index 56813f3b0b..0daa0cdd0b 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -33,6 +33,9 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri verify_token_balances_for_identity_ids: 0, verify_token_balances_for_identity_id: 0, verify_token_infos_for_identity_ids: 0, + verify_token_infos_for_identity_id: 0, + verify_token_statuses: 0, + verify_token_total_supply_and_aggregated_identity_balance: 0, }, single_document: DriveVerifySingleDocumentMethodVersions { verify_proof: 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 26c64a4d7c..9dc5f2d253 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -237,6 +237,11 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_version: 0, default_current_version: 0, }, + token_total_supply: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }, validator_queries: DriveAbciQueryValidatorVersions { proposed_block_counts_by_evonode_ids: FeatureVersionBounds {