diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ce363420efb..f2373424b67 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -66,7 +66,7 @@ RUN set -ex; \ rm /tmp/cargo-binstall; \ cargo binstall -V -RUN cargo binstall wasm-bindgen-cli@0.2.86 --locked \ +RUN cargo binstall wasm-bindgen-cli@0.2.99 --locked \ --no-discover-github-token \ --disable-telemetry \ --no-track \ diff --git a/.github/actions/librocksdb/action.yaml b/.github/actions/librocksdb/action.yaml index 217e2745eb8..c35e8459233 100644 --- a/.github/actions/librocksdb/action.yaml +++ b/.github/actions/librocksdb/action.yaml @@ -6,9 +6,9 @@ name: "librocksdb" description: "Build and install librocksdb" inputs: version: - description: RocksDB version, eg. "8.10.2" + description: RocksDB version, eg. "9.9.3" required: false - default: "8.10.2" + default: "9.9.3" force: description: Force rebuild required: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 269798a2ff6..d1d31d6613f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,14 +70,20 @@ jobs: if: ${{ steps.check-artifact.outputs.exists != 'true' }} - name: Install wasm-bindgen-cli - run: cargo binstall wasm-bindgen-cli@0.2.86 + run: cargo binstall wasm-bindgen-cli@0.2.99 + if: ${{ steps.check-artifact.outputs.exists != 'true' }} + + - name: Install Binaryen + run: | + wget https://github.com/WebAssembly/binaryen/releases/download/version_121/binaryen-version_121-x86_64-linux.tar.gz -P /tmp + tar -xzf /tmp/binaryen-version_121-x86_64-linux.tar.gz -C /tmp + sudo cp -r /tmp/binaryen-version_121/* /usr/local/ if: ${{ steps.check-artifact.outputs.exists != 'true' }} - name: Build packages run: yarn build env: CARGO_BUILD_PROFILE: release - if: ${{ steps.check-artifact.outputs.exists != 'true' }} - name: Set suffix diff --git a/.github/workflows/tests-build-js.yml b/.github/workflows/tests-build-js.yml index a36bd91e2c0..3223203e297 100644 --- a/.github/workflows/tests-build-js.yml +++ b/.github/workflows/tests-build-js.yml @@ -50,7 +50,14 @@ jobs: if: ${{ steps.check-artifact.outputs.exists != 'true' }} - name: Install wasm-bindgen-cli - run: cargo binstall wasm-bindgen-cli@0.2.86 + run: cargo binstall wasm-bindgen-cli@0.2.99 + if: ${{ steps.check-artifact.outputs.exists != 'true' }} + + - name: Install Binaryen + run: | + wget https://github.com/WebAssembly/binaryen/releases/download/version_121/binaryen-version_121-x86_64-linux.tar.gz -P /tmp + tar -xzf /tmp/binaryen-version_121-x86_64-linux.tar.gz -C /tmp + sudo cp -r /tmp/binaryen-version_121/* /usr/local/ if: ${{ steps.check-artifact.outputs.exists != 'true' }} - name: Build JS packages diff --git a/.pnp.cjs b/.pnp.cjs index c6426203740..0aab8146f66 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -8610,7 +8610,7 @@ const RAW_RUNTIME_STATE = ["semver", "npm:7.5.3"],\ ["sinon", "npm:17.0.1"],\ ["sinon-chai", "virtual:e2d057e7cc143d3cb9bec864f4a2d862441b5a09f81f8e6c46e7a098cbc89e4d07017cc6e2e2142d5704bb55da853cbec2d025ebc0b30e8696c31380c00f2c7d#npm:3.7.0"],\ - ["systeminformation", "npm:5.22.11"],\ + ["systeminformation", "npm:5.25.11"],\ ["table", "npm:6.8.1"],\ ["tar", "npm:7.4.3"],\ ["wrap-ansi", "npm:7.0.0"]\ @@ -18111,10 +18111,10 @@ const RAW_RUNTIME_STATE = }]\ ]],\ ["systeminformation", [\ - ["npm:5.22.11", {\ - "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.22.11-e704a1605b/node_modules/systeminformation/",\ + ["npm:5.25.11", {\ + "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.25.11-e1c9348b68/node_modules/systeminformation/",\ "packageDependencies": [\ - ["systeminformation", "npm:5.22.11"]\ + ["systeminformation", "npm:5.25.11"]\ ],\ "linkType": "HARD"\ }]\ diff --git a/.yarn/cache/fsevents-patch-19706e7e35-10.zip b/.yarn/cache/fsevents-patch-19706e7e35-10.zip new file mode 100644 index 00000000000..aff1ab12ce5 Binary files /dev/null and b/.yarn/cache/fsevents-patch-19706e7e35-10.zip differ diff --git a/.yarn/cache/systeminformation-npm-5.22.11-e704a1605b-315cd3f2cc.zip b/.yarn/cache/systeminformation-npm-5.22.11-e704a1605b-315cd3f2cc.zip deleted file mode 100644 index 0160773949a..00000000000 Binary files a/.yarn/cache/systeminformation-npm-5.22.11-e704a1605b-315cd3f2cc.zip and /dev/null differ diff --git a/.yarn/cache/systeminformation-npm-5.25.11-e1c9348b68-9a43bb8991.zip b/.yarn/cache/systeminformation-npm-5.25.11-e1c9348b68-9a43bb8991.zip new file mode 100644 index 00000000000..dcae174b0f4 Binary files /dev/null and b/.yarn/cache/systeminformation-npm-5.25.11-e1c9348b68-9a43bb8991.zip differ diff --git a/.yarnrc.yml b/.yarnrc.yml index 148512db4c8..73822ee10f8 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -21,6 +21,8 @@ npmAuditExcludePackages: - levelup # TODO: Update leveldb - deferred-leveldown # TODO: Update leveldb - abstract-leveldown # TODO: Update leveldb + - level-errors # TODO: Update leveldb + - level-concat-iterator # TODO: Update leveldb packageExtensions: "@dashevo/protobufjs@*": diff --git a/CHANGELOG.md b/CHANGELOG.md index e1422f602c4..2151c906422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,161 @@ +## [1.8.0](https://github.com/dashpay/platform/compare/v1.7.1...v1.8.0) (2025-01-16) + + +### Features + +* **platform:** distribute prefunded specialized balances after vote ([#2422](https://github.com/dashpay/platform/issues/2422)) +* **platform:** using new rust based bls library ([#2424](https://github.com/dashpay/platform/issues/2424)) + + +### Bug Fixes + +* **drive-abci:** document purchase on mutable document from different epoch had issue ([#2420](https://github.com/dashpay/platform/issues/2420)) +* **drive:** more than one key was returned when expecting only one result ([#2421](https://github.com/dashpay/platform/issues/2421)) +* **sdk:** failed to deserialize consensus error ([#2410](https://github.com/dashpay/platform/issues/2410)) +* try DriveDocumentQuery from DocumentQuery start field ([#2407](https://github.com/dashpay/platform/issues/2407)) +* **drive-abci** rebroadcasting should not only take first 2 quorums too ([#2425](https://github.com/dashpay/platform/issues/2425)) +* **dashmate:** local network starting issues ([#2394](https://github.com/dashpay/platform/issues/2394)) +* **dashmate:** some group commands fail with mtime not found ([#2400](https://github.com/dashpay/platform/issues/2400)) +* emergency hard fork to fix masternode voting ([#2397](https://github.com/dashpay/platform/issues/2397)) + + +### Tests + +* unify identity versioned cost coverage ([#2416](https://github.com/dashpay/platform/issues/2416)) +* **sdk:** generate test vectors using testnet ([#2381](https://github.com/dashpay/platform/issues/2381)) + + +### Miscellaneous Chores + +* **drive:** increase withdrawal limits to 2000 Dash per day ([#2287](https://github.com/dashpay/platform/issues/2287)) +* fix test suite configuration script ([#2402](https://github.com/dashpay/platform/issues/2402)) +* resolve NPM audit warnings ([#2417](https://github.com/dashpay/platform/issues/2417)) +* remove deprecated check_network_version.sh ([#2084](https://github.com/dashpay/platform/issues/2084)) +* update bls library ([#2424](https://github.com/dashpay/platform/issues/2424)) + + +### Code Refactoring + +* **platform:** replace bls library ([#2257](https://github.com/dashpay/platform/issues/2257)) +* **dpp:** using deprecated param to init wasm module ([#2399](https://github.com/dashpay/platform/issues/2399)) + + +### Performance Improvements + +* **dpp:** reduce JS binding size by 3x ([#2396](https://github.com/dashpay/platform/issues/2396)) + + +### Continuous Integration + +* fix artifact upload issue on release build ([#2389](https://github.com/dashpay/platform/issues/2389)) + + +### Build System + +* bump wasm-bindgen to 0.2.99 ([#2395](https://github.com/dashpay/platform/issues/2395)) +* update rust to 1.83 ([#2393](https://github.com/dashpay/platform/issues/2393)) + + + +## [1.8.0-rc.1](https://github.com/dashpay/platform/compare/v1.8.0-dev.2...v1.8.0-rc.1) (2025-01-15) + + +### Features + +* **platform:** distribute prefunded specialized balances after vote ([#2422](https://github.com/dashpay/platform/issues/2422)) + + +### Bug Fixes + +* **drive-abci:** document purchase on mutable document from different epoch had issue ([#2420](https://github.com/dashpay/platform/issues/2420)) +* **drive:** more than one key was returned when expecting only one result ([#2421](https://github.com/dashpay/platform/issues/2421)) +* **sdk:** failed to deserialize consensus error ([#2410](https://github.com/dashpay/platform/issues/2410)) +* try DriveDocumentQuery from DocumentQuery start field ([#2407](https://github.com/dashpay/platform/issues/2407)) + + +### Tests + +* unify identity versioned cost coverage ([#2416](https://github.com/dashpay/platform/issues/2416)) + + +### Miscellaneous Chores + +* **drive:** increase withdrawal limits to 2000 Dash per day ([#2287](https://github.com/dashpay/platform/issues/2287)) +* fix test suite configuration script ([#2402](https://github.com/dashpay/platform/issues/2402)) +* resolve NPM audit warnings ([#2417](https://github.com/dashpay/platform/issues/2417)) +* update bls library ([#2424](https://github.com/dashpay/platform/issues/2424)) + + + +## [1.8.0-dev.2](https://github.com/dashpay/platform/compare/v1.8.0-dev.1...v1.8.0-dev.2) (2024-12-19) + +### ⚠ BREAKING CHANGES + +* On epoch 13, masternode vote state transition validation logic will be changed. Nodes which aren't upgraded to this version will halt (#2397) +* Rust 1.83 is required to build the project (#2398) + +### Bug Fixes + +* **dashmate:** local network starting issues ([#2394](https://github.com/dashpay/platform/issues/2394)) +* **dashmate:** some group commands fail with mtime not found ([#2400](https://github.com/dashpay/platform/issues/2400)) +* emergency hard fork to fix masternode voting ([#2397](https://github.com/dashpay/platform/issues/2397)) + + +### Performance Improvements + +* **dpp:** reduce JS binding size by 3x ([#2396](https://github.com/dashpay/platform/issues/2396)) + + +### Build System + +* bump wasm-bindgen to 0.2.99 ([#2395](https://github.com/dashpay/platform/issues/2395)) +* update rust to 1.83 ([#2393](https://github.com/dashpay/platform/issues/2393)) + + +### Code Refactoring + +* **dpp:** using deprecated param to init wasm module ([#2399](https://github.com/dashpay/platform/issues/2399)) + + +### [1.7.1](https://github.com/dashpay/platform/compare/v1.7.0...v1.7.1) (2024-12-19) + +### ⚠ BREAKING CHANGES + +* On epoch 13, masternode vote state transition validation logic will be changed. Nodes which aren't upgraded to this version will halt (#2397) +* Rust 1.83 is required to build the project (#2398) + +### Bug Fixes + +* emergency hard fork to fix masternode voting ([#2397](https://github.com/dashpay/platform/issues/2397)) + + +### Build System + +* update rust to 1.83 - backport [#2393](https://github.com/dashpay/platform/issues/2393) to v1.7 ([#2398](https://github.com/dashpay/platform/issues/2398)) + + +## [1.8.0-dev.1](https://github.com/dashpay/platform/compare/v1.7.0...v1.8.0-dev.1) (2024-12-16) + +### Continuous Integration + +* fix artifact upload issue on release build ([#2389](https://github.com/dashpay/platform/issues/2389)) + + +### Miscellaneous Chores + +* remove deprecated check_network_version.sh ([#2084](https://github.com/dashpay/platform/issues/2084)) + + +### Tests + +* **sdk:** generate test vectors using testnet ([#2381](https://github.com/dashpay/platform/issues/2381)) + + +### Code Refactoring + +* **platform:** replace bls library ([#2257](https://github.com/dashpay/platform/issues/2257)) + + ### [1.7.0](https://github.com/dashpay/platform/compare/v1.6.2...v1.7.0) (2024-12-13) diff --git a/Cargo.lock b/Cargo.lock index 72f7570190b..e8c68108b7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -213,7 +213,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -224,7 +224,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -304,7 +304,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -407,7 +407,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.75", + "syn 2.0.96", "which", ] @@ -428,7 +428,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -438,7 +438,7 @@ source = "git+https://github.com/dashpay/rs-bip37-bloom-filter?branch=develop#35 dependencies = [ "bitvec", "murmur3", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -506,7 +506,7 @@ dependencies = [ "arrayvec", "cc", "cfg-if", - "constant_time_eq 0.3.1", + "constant_time_eq", ] [[package]] @@ -541,12 +541,11 @@ dependencies = [ [[package]] name = "blsful" -version = "3.0.0-pre6" +version = "3.0.0-pre8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9de4566ea9f21109f6b3f11551b591ff22683ff47c3a30d97e2feb23257427" +checksum = "384e5e9866cb7f830f06a6633ba998697d5a826e99e8c78376deaadd33cda7be" dependencies = [ "anyhow", - "arrayref", "blstrs_plus", "hex", "hkdf", @@ -560,7 +559,7 @@ dependencies = [ "sha2", "sha3", "subtle", - "thiserror", + "thiserror 2.0.11", "uint-zigzag", "vsss-rs", "zeroize", @@ -616,7 +615,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", "syn_derive", ] @@ -739,7 +738,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "check-features" -version = "1.7.0" +version = "1.8.0" dependencies = [ "toml", ] @@ -756,7 +755,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -862,7 +861,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -879,12 +878,11 @@ checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" -version = "2.1.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -941,24 +939,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_time_eq" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "core-foundation" version = "0.9.4" @@ -993,6 +979,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -1125,12 +1126,12 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] name = "dapi-grpc" -version = "1.7.0" +version = "1.8.0" dependencies = [ "dapi-grpc-macros", "futures-core", @@ -1146,12 +1147,12 @@ dependencies = [ [[package]] name = "dapi-grpc-macros" -version = "1.7.0" +version = "1.8.0" dependencies = [ "dapi-grpc", "heck 0.5.0", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -1175,7 +1176,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -1186,14 +1187,15 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] name = "dash-sdk" -version = "1.7.0" +version = "1.8.0" dependencies = [ "arc-swap", + "assert_matches", "async-trait", "backon", "base64 0.22.1", @@ -1205,7 +1207,7 @@ dependencies = [ "dapi-grpc-macros", "dashcore-rpc", "data-contracts", - "derive_more 1.0.0", + "derive_more", "dotenvy", "dpp", "drive", @@ -1216,11 +1218,12 @@ dependencies = [ "http", "lru", "rs-dapi-client", + "rustls-pemfile", "sanitize-filename", "serde", "serde_json", "test-case", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-test", "tokio-util", @@ -1231,8 +1234,8 @@ dependencies = [ [[package]] name = "dashcore" -version = "0.34.0" -source = "git+https://github.com/dashpay/rust-dashcore?tag=0.34.0#4c61ab617ca9f86f84484607014a7e8e0baba960" +version = "0.35.0" +source = "git+https://github.com/dashpay/rust-dashcore?tag=v0.35.0#521a76bfd7eaa90d2d89dc576808ec5772544f07" dependencies = [ "anyhow", "bech32", @@ -1254,16 +1257,14 @@ dependencies = [ [[package]] name = "dashcore-private" version = "0.1.0" -source = "git+https://github.com/dashpay/rust-dashcore?tag=0.34.0#4c61ab617ca9f86f84484607014a7e8e0baba960" +source = "git+https://github.com/dashpay/rust-dashcore?tag=v0.35.0#521a76bfd7eaa90d2d89dc576808ec5772544f07" [[package]] name = "dashcore-rpc" -version = "0.15.13" -source = "git+https://github.com/dashpay/rust-dashcore-rpc?tag=v0.15.13#88dfef0dc04cbe8f4b0d24e9aabfae8ca126c74a" +version = "0.16.0" +source = "git+https://github.com/dashpay/rust-dashcore-rpc?tag=v0.16.0#099e871a64bbff1faf9c1d56014b612a1da1f3e0" dependencies = [ - "dashcore-private", "dashcore-rpc-json", - "env_logger 0.10.2", "hex", "jsonrpc", "log", @@ -1273,8 +1274,8 @@ dependencies = [ [[package]] name = "dashcore-rpc-json" -version = "0.15.13" -source = "git+https://github.com/dashpay/rust-dashcore-rpc?tag=v0.15.13#88dfef0dc04cbe8f4b0d24e9aabfae8ca126c74a" +version = "0.16.0" +source = "git+https://github.com/dashpay/rust-dashcore-rpc?tag=v0.16.0#099e871a64bbff1faf9c1d56014b612a1da1f3e0" dependencies = [ "bincode", "dashcore", @@ -1288,7 +1289,7 @@ dependencies = [ [[package]] name = "dashcore_hashes" version = "0.14.0" -source = "git+https://github.com/dashpay/rust-dashcore?tag=0.34.0#4c61ab617ca9f86f84484607014a7e8e0baba960" +source = "git+https://github.com/dashpay/rust-dashcore?tag=v0.35.0#521a76bfd7eaa90d2d89dc576808ec5772544f07" dependencies = [ "dashcore-private", "secp256k1", @@ -1297,17 +1298,17 @@ dependencies = [ [[package]] name = "dashpay-contract" -version = "1.7.0" +version = "1.8.0" dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "data-contracts" -version = "1.7.0" +version = "1.8.0" dependencies = [ "dashpay-contract", "dpns-contract", @@ -1316,11 +1317,17 @@ dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", "wallet-utils-contract", "withdrawals-contract", ] +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + [[package]] name = "delegate" version = "0.13.0" @@ -1329,7 +1336,7 @@ checksum = "5060bb0febb73fa907273f8a7ed17ab4bf831d585eac835b28ec24a1e2460956" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -1360,20 +1367,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -1393,7 +1387,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", "unicode-xid", ] @@ -1422,7 +1416,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -1439,17 +1433,17 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dpns-contract" -version = "1.7.0" +version = "1.8.0" dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "dpp" -version = "1.7.0" +version = "1.8.0" dependencies = [ "anyhow", "assert_matches", @@ -1462,9 +1456,9 @@ dependencies = [ "ciborium 0.2.0", "dashcore", "data-contracts", - "derive_more 1.0.0", + "derive_more", "dpp", - "env_logger 0.11.5", + "env_logger", "getrandom", "hex", "indexmap 2.7.0", @@ -1493,13 +1487,13 @@ dependencies = [ "sha2", "strum", "test-case", - "thiserror", + "thiserror 1.0.64", "tokio", ] [[package]] name = "drive" -version = "1.7.0" +version = "1.8.0" dependencies = [ "arc-swap", "assert_matches", @@ -1510,7 +1504,7 @@ dependencies = [ "chrono", "ciborium 0.2.0", "criterion", - "derive_more 1.0.0", + "derive_more", "dpp", "enum-map", "grovedb", @@ -1534,13 +1528,13 @@ dependencies = [ "serde_json", "sqlparser", "tempfile", - "thiserror", + "thiserror 1.0.64", "tracing", ] [[package]] name = "drive-abci" -version = "1.7.0" +version = "1.8.0" dependencies = [ "arc-swap", "assert_matches", @@ -1556,7 +1550,7 @@ dependencies = [ "dapi-grpc", "dashcore-rpc", "delegate", - "derive_more 1.0.0", + "derive_more", "dotenvy", "dpp", "drive", @@ -1585,7 +1579,7 @@ dependencies = [ "strategy-tests", "tempfile", "tenderdash-abci", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", "tracing", @@ -1595,11 +1589,11 @@ dependencies = [ [[package]] name = "drive-proof-verifier" -version = "1.7.0" +version = "1.8.0" dependencies = [ "bincode", "dapi-grpc", - "derive_more 1.0.0", + "derive_more", "dpp", "drive", "hex", @@ -1609,7 +1603,7 @@ dependencies = [ "serde", "serde_json", "tenderdash-abci", - "thiserror", + "thiserror 1.0.64", "tracing", ] @@ -1620,7 +1614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9c8d6ea916fadcd87e3d1ff4802b696d717c83519b47e76f267ab77e536dd5a" dependencies = [ "ed-derive", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -1726,7 +1720,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -1739,19 +1733,6 @@ dependencies = [ "regex", ] -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.11.5" @@ -1811,28 +1792,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure", -] - [[package]] name = "fancy-regex" version = "0.13.0" @@ -1852,12 +1811,12 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "feature-flags-contract" -version = "1.7.0" +version = "1.8.0" dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2032,7 +1991,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -2138,15 +2097,13 @@ dependencies = [ [[package]] name = "grovedb" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d91e8f87926c834c7338d0c69a48816c043e0cddf0062a8a567483db2fb1e24" +checksum = "ebf36cc41af86d8ccb8b7f64fd15006cd83ec979c49cd2ad30628bf855c54d7d" dependencies = [ "axum", "bincode", - "bitvec", "blake3", - "derive_more 0.99.18", "grovedb-costs", "grovedb-merk", "grovedb-path", @@ -2159,12 +2116,11 @@ dependencies = [ "indexmap 2.7.0", "integer-encoding", "intmap", - "itertools 0.12.1", - "nohash-hasher", + "itertools 0.14.0", "reqwest", "sha2", "tempfile", - "thiserror", + "thiserror 2.0.11", "tokio", "tokio-util", "tower-http", @@ -2173,40 +2129,38 @@ dependencies = [ [[package]] name = "grovedb-costs" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360f7c8d3b20beafcbf3cde8754bbcfd201ae2a30ec7594a4b9678fd2fa3c7a8" +checksum = "9cc526a58bdca58cb86340632081e27264e3557a73608cf29f6738ad9bfab316" dependencies = [ "integer-encoding", "intmap", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "grovedb-epoch-based-storage-flags" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acec1b6962d99d7b079c0fd1532cd3a2c83a3d659ffd9fcf02edda4599334bb4" +checksum = "abd5f01eb50ff57b2c24e856377684d42dacdbd04de7c0189bf2e0e0cd109692" dependencies = [ "grovedb-costs", "hex", "integer-encoding", "intmap", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "grovedb-merk" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72057865f239fdd24f92eaa8668acc0d618da168f330546577a62eda1701210e" +checksum = "0ce3b133a76e9935f3a57e08598769849d79df582244e1ac99509177e23c2605" dependencies = [ "bincode", "blake3", - "byteorder", "colored", "ed", - "failure", "grovedb-costs", "grovedb-path", "grovedb-storage", @@ -2217,21 +2171,20 @@ dependencies = [ "integer-encoding", "num_cpus", "rand", - "thiserror", - "time", + "thiserror 2.0.11", ] [[package]] name = "grovedb-path" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d96cc6106e5ca88e548d66f130b877b664da78be226dfdba555fc210f8508f4" +checksum = "67dc8bc00b9be473f7b25670d1422daadd706c9b09ed6aa5cf2caf8722a487ac" [[package]] name = "grovedb-storage" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c9b59bc9fa7123b8485f87f88a886dd109e7aff5f34a29a3812cb64eb897ff" +checksum = "905cff776de89b9ee1e96979861e254b0912170b35d89678ad782f487a22a2e3" dependencies = [ "blake3", "grovedb-costs", @@ -2244,34 +2197,34 @@ dependencies = [ "rocksdb", "strum", "tempfile", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "grovedb-version" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4be0c1a1ef97068fe93212e7b6f349e0b44a9fc90063c8c28e110cfb8c2fcb2" +checksum = "a987e051c8c9cf8fa381b29b243d4951f8c1f24f9c90ceed52afca3ac460986c" dependencies = [ - "thiserror", + "thiserror 2.0.11", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "grovedb-visualize" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5865f4335eb99644512a7d80d6b1698ba1099a8268fdfd3ffb1a3a32dcb4af28" +checksum = "56eee6f57d324505611de0042af2b6b9933235e704a1a6542ff7ba5b5c56f64e" dependencies = [ "hex", - "itertools 0.12.1", + "itertools 0.14.0", ] [[package]] name = "grovedbg-types" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921b9a29facf9d3f0de667cd1da083a34695ede9e7bfacd74bb5bd29f8f7c178" +checksum = "7cfa37a90579ba2c71e074d6047c1dcfc19caa458fbcefd4e8e31a02f6a9fe38" dependencies = [ "serde", "serde_with 3.9.0", @@ -2688,9 +2641,9 @@ checksum = "0d762194228a2f1c11063e46e32e5acb96e66e906382b9eb5441f2e0504bbd5a" [[package]] name = "intmap" -version = "2.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee87fd093563344074bacf24faa0bb0227fb6969fb223e922db798516de924d6" +checksum = "615970152acd1ae5f372f98eae7fab7ea63d4ee022cf655cf7079883bde9c3ee" dependencies = [ "serde", ] @@ -2754,6 +2707,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" @@ -2771,10 +2733,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2786,19 +2749,19 @@ checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] name = "json-schema-compatibility-validator" -version = "1.7.0" +version = "1.8.0" dependencies = [ "assert_matches", "json-patch", "json-schema-compatibility-validator", "once_cell", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -2879,19 +2842,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "librocksdb-sys" -version = "0.16.0+8.10.0" +version = "0.17.1+9.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3d60bc059831dc1c83903fb45c103f75db65c5a7bf22272764d9cc683e348c" +checksum = "2b7869a512ae9982f4d46ba482c2a304f1efd80c6412a3d4bf57bb79a619679f" dependencies = [ "bindgen 0.69.4", "bzip2-sys", "cc", - "glob", "libc", "libz-sys", "lz4-sys", @@ -2962,14 +2924,24 @@ dependencies = [ "libc", ] +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + [[package]] name = "masternode-reward-shares-contract" -version = "1.7.0" +version = "1.8.0" dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -3030,7 +3002,7 @@ dependencies = [ "metrics", "metrics-util", "quanta", - "thiserror", + "thiserror 1.0.64", "tokio", "tracing", ] @@ -3124,7 +3096,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3146,7 +3118,7 @@ dependencies = [ "rustc_version", "smallvec", "tagptr", - "thiserror", + "thiserror 1.0.64", "triomphe", "uuid", ] @@ -3276,7 +3248,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3369,7 +3341,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3416,7 +3388,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3478,18 +3450,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", + "windows-targets", ] [[package]] @@ -3500,14 +3461,12 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", "hmac", - "password-hash", - "sha2", ] [[package]] @@ -3549,7 +3508,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3582,7 +3541,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platform-serialization" -version = "1.7.0" +version = "1.8.0" dependencies = [ "bincode", "platform-version", @@ -3590,17 +3549,17 @@ dependencies = [ [[package]] name = "platform-serialization-derive" -version = "1.7.0" +version = "1.8.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", "virtue 0.0.17", ] [[package]] name = "platform-value" -version = "1.7.0" +version = "1.8.0" dependencies = [ "base64 0.22.1", "bincode", @@ -3615,36 +3574,36 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror", + "thiserror 1.0.64", "treediff", ] [[package]] name = "platform-value-convertible" -version = "1.7.0" +version = "1.8.0" dependencies = [ "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] name = "platform-version" -version = "1.7.0" +version = "1.8.0" dependencies = [ "bincode", "grovedb-version", "once_cell", - "thiserror", + "thiserror 1.0.64", "versioned-feature-core 1.0.0 (git+https://github.com/dashpay/versioned-feature-core)", ] [[package]] name = "platform-versioning" -version = "1.7.0" +version = "1.8.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3739,7 +3698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -3786,9 +3745,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -3820,7 +3779,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.75", + "syn 2.0.96", "tempfile", ] @@ -3834,7 +3793,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4125,9 +4084,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd13e55d6d7b8cd0ea569161127567cd587676c99f4472f779a0279aa60a7a7" +checksum = "26ec73b20525cb235bad420f911473b69f9fe27cc856c5461bccd7e4af037f43" dependencies = [ "libc", "librocksdb-sys", @@ -4135,7 +4094,7 @@ dependencies = [ [[package]] name = "rs-dapi-client" -version = "1.7.0" +version = "1.8.0" dependencies = [ "backon", "chrono", @@ -4148,7 +4107,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.64", "tokio", "tracing", ] @@ -4396,7 +4355,7 @@ dependencies = [ [[package]] name = "serde-wasm-bindgen" version = "0.5.0" -source = "git+https://github.com/QuantumExplorer/serde-wasm-bindgen?branch=feat/not_human_readable#121d1f7fbf62cb97f74b91626a1b23851098cc82" +source = "git+https://github.com/QuantumExplorer/serde-wasm-bindgen?branch=feat%2Fnot_human_readable#121d1f7fbf62cb97f74b91626a1b23851098cc82" dependencies = [ "js-sys", "serde", @@ -4429,7 +4388,7 @@ checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4463,7 +4422,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4530,7 +4489,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4542,7 +4501,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4634,7 +4593,7 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simple-signer" -version = "1.7.0" +version = "1.8.0" dependencies = [ "base64 0.22.1", "bincode", @@ -4719,7 +4678,7 @@ dependencies = [ [[package]] name = "strategy-tests" -version = "1.7.0" +version = "1.8.0" dependencies = [ "bincode", "dpp", @@ -4761,7 +4720,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4792,9 +4751,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -4810,7 +4769,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4828,18 +4787,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "system-configuration" version = "0.6.1" @@ -4889,7 +4836,7 @@ dependencies = [ [[package]] name = "tenderdash-abci" version = "1.2.1+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1+1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" dependencies = [ "bytes", "futures", @@ -4898,7 +4845,7 @@ dependencies = [ "semver", "serde_json", "tenderdash-proto", - "thiserror", + "thiserror 1.0.64", "tokio", "tokio-util", "tracing", @@ -4910,11 +4857,11 @@ dependencies = [ [[package]] name = "tenderdash-proto" version = "1.2.1+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1+1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" dependencies = [ "bytes", "chrono", - "derive_more 1.0.0", + "derive_more", "flex-error", "num-derive", "num-traits", @@ -4929,7 +4876,7 @@ dependencies = [ [[package]] name = "tenderdash-proto-compiler" version = "1.2.1+1.3.0" -source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1+1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" +source = "git+https://github.com/dashpay/rs-tenderdash-abci?tag=v1.2.1%2B1.3.0#aad72f4d25816bdf0f584ee4ba3cd383addf8a33" dependencies = [ "fs_extra", "prost-build", @@ -4938,16 +4885,7 @@ dependencies = [ "tonic-build", "ureq", "walkdir", - "zip 2.2.0", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", + "zip", ] [[package]] @@ -4974,7 +4912,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -4985,7 +4923,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", "test-case-core", ] @@ -4995,38 +4933,38 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.64", ] [[package]] -name = "thiserror-impl" -version = "1.0.64" +name = "thiserror" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.75", + "thiserror-impl 2.0.11", ] [[package]] -name = "thiserror-impl-no-std" -version = "2.0.2" +name = "thiserror-impl" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.96", ] [[package]] -name = "thiserror-no-std" -version = "2.0.2" +name = "thiserror-impl" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ - "thiserror-impl-no-std", + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] @@ -5131,7 +5069,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -5293,13 +5231,13 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] name = "tower" version = "0.4.13" -source = "git+https://github.com/QuantumExplorer/tower?branch=fix/indexMap2OnV0413#5286f8c605d10f48d51254f2434c5ab3fc5d7779" +source = "git+https://github.com/QuantumExplorer/tower?branch=fix%2FindexMap2OnV0413#5286f8c605d10f48d51254f2434c5ab3fc5d7779" dependencies = [ "futures-core", "futures-util", @@ -5343,12 +5281,12 @@ dependencies = [ [[package]] name = "tower-layer" version = "0.3.2" -source = "git+https://github.com/QuantumExplorer/tower?branch=fix/indexMap2OnV0413#5286f8c605d10f48d51254f2434c5ab3fc5d7779" +source = "git+https://github.com/QuantumExplorer/tower?branch=fix%2FindexMap2OnV0413#5286f8c605d10f48d51254f2434c5ab3fc5d7779" [[package]] name = "tower-service" version = "0.3.2" -source = "git+https://github.com/QuantumExplorer/tower?branch=fix/indexMap2OnV0413#5286f8c605d10f48d51254f2434c5ab3fc5d7779" +source = "git+https://github.com/QuantumExplorer/tower?branch=fix%2FindexMap2OnV0413#5286f8c605d10f48d51254f2434c5ab3fc5d7779" [[package]] name = "tracing" @@ -5370,7 +5308,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -5589,9 +5527,9 @@ checksum = "7302ac74a033bf17b6e609ceec0f891ca9200d502d31f02dc7908d3d98767c9d" [[package]] name = "vsss-rs" -version = "5.0.0-rc1" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9860fb75908021ae4cc125917c9763134f7f236a716d181ed644627783230c5d" +checksum = "fec4ebcc5594130c31b49594d55c0583fe80621f252f570b222ca4845cafd3cf" dependencies = [ "crypto-bigint", "elliptic-curve", @@ -5603,7 +5541,6 @@ dependencies = [ "serde", "sha3", "subtle", - "thiserror-no-std", "zeroize", ] @@ -5619,12 +5556,12 @@ dependencies = [ [[package]] name = "wallet-utils-contract" -version = "1.7.0" +version = "1.8.0" dependencies = [ "platform-value", "platform-version", "serde_json", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -5644,46 +5581,47 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5691,26 +5629,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-dpp" -version = "1.7.0" +version = "1.8.0" dependencies = [ "anyhow", "async-trait", @@ -5725,7 +5663,7 @@ dependencies = [ "serde", "serde-wasm-bindgen", "serde_json", - "thiserror", + "thiserror 1.0.64", "wasm-bindgen", "wasm-bindgen-futures", "wasm-logger", @@ -5745,9 +5683,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -5811,7 +5749,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -5822,7 +5760,7 @@ checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ "windows-result", "windows-strings", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -5831,7 +5769,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -5841,16 +5779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -5859,7 +5788,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -5868,22 +5797,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -5892,46 +5806,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5944,48 +5840,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -6012,7 +5884,7 @@ dependencies = [ [[package]] name = "withdrawals-contract" -version = "1.7.0" +version = "1.8.0" dependencies = [ "num_enum 0.5.11", "platform-value", @@ -6020,7 +5892,7 @@ dependencies = [ "serde", "serde_json", "serde_repr", - "thiserror", + "thiserror 1.0.64", ] [[package]] @@ -6067,7 +5939,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.96", ] [[package]] @@ -6094,27 +5966,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq 0.1.5", - "crc32fast", - "crossbeam-utils", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd", + "syn 2.0.96", ] [[package]] @@ -6123,24 +5975,36 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" dependencies = [ + "aes", "arbitrary", + "bzip2", + "constant_time_eq", "crc32fast", "crossbeam-utils", + "deflate64", "displaydoc", "flate2", + "hmac", "indexmap 2.7.0", + "lzma-rs", "memchr", - "thiserror", + "pbkdf2", + "rand", + "sha1", + "thiserror 1.0.64", + "time", + "zeroize", "zopfli", + "zstd", ] [[package]] name = "zip-extensions" -version = "0.6.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecf62554c4ff96bce01a7ef123d160c3ffe9180638820f8b4d545c65b221b8c" +checksum = "386508a00aae1d8218b9252a41f59bba739ccee3f8e420bb90bcb1c30d960d4a" dependencies = [ - "zip 0.6.6", + "zip", ] [[package]] @@ -6159,20 +6023,19 @@ dependencies = [ [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ - "libc", "zstd-sys", ] diff --git a/Dockerfile b/Dockerfile index 5b2ff5882a1..27d92abbb08 100644 --- a/Dockerfile +++ b/Dockerfile @@ -283,7 +283,7 @@ ONBUILD ARG CARGO_BUILD_PROFILE=dev RUN --mount=type=secret,id=AWS <> ~/.zshrc` or `echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.bash_profile` depending on your default shell. You can find your default shell with `echo $SHELL` - Reload your shell with `source ~/.zshrc` or `source ~/.bash_profile` - - `cargo install wasm-bindgen-cli@0.2.86` + - `cargo install wasm-bindgen-cli@0.2.99` - *double-check that wasm-bindgen-cli version above matches wasm-bindgen version in Cargo.lock file* - *Depending on system, additional packages may need to be installed as a prerequisite for wasm-bindgen-cli. If anything is missing, installation will error and prompt what packages are missing (i.e. clang, llvm, libssl-dev)* - essential build tools - example for Debian/Ubuntu: `apt install -y build-essential libssl-dev pkg-config clang cmake llvm` diff --git a/package.json b/package.json index 1fb1219cca5..c8df6e9b6b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/platform", - "version": "1.7.0", + "version": "1.8.0", "private": true, "scripts": { "setup": "yarn install && yarn run build && yarn run configure", diff --git a/packages/bench-suite/package.json b/packages/bench-suite/package.json index a6aafba96c1..9c7c851e6b5 100644 --- a/packages/bench-suite/package.json +++ b/packages/bench-suite/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/bench-suite", "private": true, - "version": "1.7.0", + "version": "1.8.0", "description": "Dash Platform benchmark tool", "scripts": { "bench": "node ./bin/bench.js", diff --git a/packages/check-features/Cargo.toml b/packages/check-features/Cargo.toml index dfb68a8e907..c4dd095d520 100644 --- a/packages/check-features/Cargo.toml +++ b/packages/check-features/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "check-features" -version = "1.7.0" +version = "1.8.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/packages/dapi-grpc/Cargo.toml b/packages/dapi-grpc/Cargo.toml index 6444245d9e9..2b4fe8e531e 100644 --- a/packages/dapi-grpc/Cargo.toml +++ b/packages/dapi-grpc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dapi-grpc" description = "GRPC client for Dash Platform" -version = "1.7.0" +version = "1.8.0" authors = [ "Samuel Westrich ", "Igor Markin ", diff --git a/packages/dapi-grpc/package.json b/packages/dapi-grpc/package.json index fb7696339fb..6b6a1e52dee 100644 --- a/packages/dapi-grpc/package.json +++ b/packages/dapi-grpc/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dapi-grpc", - "version": "1.7.0", + "version": "1.8.0", "description": "DAPI GRPC definition file and generated clients", "browser": "browser.js", "main": "node.js", diff --git a/packages/dapi/package.json b/packages/dapi/package.json index e1175fee939..f780aad4c9d 100644 --- a/packages/dapi/package.json +++ b/packages/dapi/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/dapi", "private": true, - "version": "1.7.0", + "version": "1.8.0", "description": "A decentralized API for the Dash network", "scripts": { "api": "node scripts/api.js", diff --git a/packages/dash-spv/package.json b/packages/dash-spv/package.json index 1c415d01cde..1467f6105bf 100644 --- a/packages/dash-spv/package.json +++ b/packages/dash-spv/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dash-spv", - "version": "2.7.0", + "version": "2.8.0", "description": "Repository containing SPV functions used by @dashevo", "main": "index.js", "scripts": { diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 68d5258ff92..1614216ad2a 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -118,7 +118,6 @@ export default function getBaseConfigFactory() { miner: { enable: false, interval: '2.5m', - mediantime: null, address: null, }, devnet: { diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index fd05cab111b..6b9092ab005 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -1056,6 +1056,16 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) }); return configFile; }, + '1.8.0': (configFile) => { + Object.entries(configFile.configs) + .forEach(([, options]) => { + delete options.core.miner.mediantime; + + options.platform.drive.abci.docker.image = 'dashpay/drive:1'; + options.platform.dapi.api.docker.image = 'dashpay/dapi:1'; + }); + return configFile; + }, }; } diff --git a/packages/dashmate/package.json b/packages/dashmate/package.json index f3d89649112..3ec7a34376c 100644 --- a/packages/dashmate/package.json +++ b/packages/dashmate/package.json @@ -1,6 +1,6 @@ { "name": "dashmate", - "version": "1.7.0", + "version": "1.8.0", "description": "Distribution package for Dash node installation", "scripts": { "lint": "eslint .", @@ -91,7 +91,7 @@ "qs": "^6.11.0", "rxjs": "^6.6.7", "semver": "^7.5.3", - "systeminformation": "^5.22.11", + "systeminformation": "^5.25.11", "table": "^6.8.1", "tar": "7.4.3", "wrap-ansi": "^7.0.0" diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index ed77019f290..0f57fbbf50d 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -349,15 +349,11 @@ export default { interval: { $ref: '#/definitions/duration', }, - mediantime: { - type: ['integer', 'null'], - minimum: 0, - }, address: { type: ['string', 'null'], }, }, - required: ['enable', 'interval', 'mediantime', 'address'], + required: ['enable', 'interval', 'address'], additionalProperties: false, }, devnet: { diff --git a/packages/dashmate/src/core/quorum/waitForMasternodeProbes.js b/packages/dashmate/src/core/quorum/waitForMasternodeProbes.js index b16197dcaf1..5e6ccb40851 100644 --- a/packages/dashmate/src/core/quorum/waitForMasternodeProbes.js +++ b/packages/dashmate/src/core/quorum/waitForMasternodeProbes.js @@ -1,14 +1,14 @@ import { LLMQ_TYPE_TEST } from '../../constants.js'; +import wait from '../../util/wait.js'; /** * Checks all mastrenodoes probes to incterconnected masternodes * * @param {RpcClient[]} rpcClients - * @param {Function} bumpMockTime * * @return {Promise} */ -async function checkProbes(rpcClients, bumpMockTime) { +async function checkProbes(rpcClients) { let masternodes = await Promise.all( rpcClients.map((rpc) => { const promise = rpc.masternode('status'); @@ -30,8 +30,6 @@ async function checkProbes(rpcClients, bumpMockTime) { .find((connection) => connection.llmqType === LLMQ_TYPE_TEST); if (!llmqConnection) { - await bumpMockTime(); - return false; } @@ -49,16 +47,12 @@ async function checkProbes(rpcClients, bumpMockTime) { // probe is not too old. Probes are retried after 50 minutes, while DKGs consider // a probe as failed after 60 minutes if (mnInfo.metaInfo.lastOutboundSuccessElapsed > 55 * 60) { - await bumpMockTime(); - return false; } // MN is expected to be offline, so let's only check that // the last probe is not too long ago } else if (mnInfo.metaInfo.lastOutboundAttemptElapsed > 55 * 60 && mnInfo.metaInfo.lastOutboundSuccessElapsed > 55 * 60) { - await bumpMockTime(); - return false; } } @@ -72,20 +66,21 @@ async function checkProbes(rpcClients, bumpMockTime) { /** * * @param {RpcClient[]} rpcClients - * @param {Function} bumpMockTime * @param {number} [timeout] * @return {Promise} */ -export default async function waitForMasternodeProbes(rpcClients, bumpMockTime, timeout = 30000) { +export default async function waitForMasternodeProbes(rpcClients, timeout = 30000) { const deadline = Date.now() + timeout; let isReady = false; while (!isReady) { - isReady = await checkProbes(rpcClients, bumpMockTime); + isReady = await checkProbes(rpcClients); if (Date.now() > deadline) { throw new Error(`waitForMasternodeProbes deadline of ${timeout} exceeded`); } + + await wait(100); } } diff --git a/packages/dashmate/src/core/quorum/waitForQuorumConnections.js b/packages/dashmate/src/core/quorum/waitForQuorumConnections.js index 465ab84c197..90d512f77d8 100644 --- a/packages/dashmate/src/core/quorum/waitForQuorumConnections.js +++ b/packages/dashmate/src/core/quorum/waitForQuorumConnections.js @@ -31,14 +31,12 @@ async function checkQuorumConnections(rpcClient, expectedConnectionsCount) { * * @param {RpcClient[]} rpcClients * @param {number} expectedConnectionsCount - * @param {Function} bumpMockTime * @param {number} [timeout] * @return {Promise} */ export default async function waitForQuorumConnections( rpcClients, expectedConnectionsCount, - bumpMockTime, timeout = 300000, ) { const deadline = Date.now() + timeout; @@ -58,8 +56,6 @@ export default async function waitForQuorumConnections( })); if (readyNodes.size < nodesToWait) { - await bumpMockTime(); - await wait(1000); } diff --git a/packages/dashmate/src/listr/tasks/resetNodeTaskFactory.js b/packages/dashmate/src/listr/tasks/resetNodeTaskFactory.js index 374c7f37043..108a53047e2 100644 --- a/packages/dashmate/src/listr/tasks/resetNodeTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/resetNodeTaskFactory.js @@ -123,14 +123,6 @@ export default function resetNodeTaskFactory( } }, }, - { - title: 'Reset dashmate\'s ephemeral data', - enabled: (ctx) => !ctx.removeConfig && !ctx.isHardReset && !ctx.isPlatformOnlyReset, - task: () => { - // TODO: We should remove it from config - config.set('core.miner.mediantime', null); - }, - }, { title: `Remove config ${config.getName()}`, enabled: (ctx) => ctx.removeConfig, diff --git a/packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js index 522509b7397..0ba938c2c14 100644 --- a/packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js @@ -212,15 +212,6 @@ export default function configureCoreTaskFactory( )); ctx.seedRpcClient = ctx.seedCoreService.getRpcClient(); - - ctx.mockTime = 0; - ctx.bumpMockTime = async (time = 1) => { - ctx.mockTime += time; - - await Promise.all( - ctx.rpcClients.map((rpcClient) => rpcClient.setMockTime(ctx.mockTime)), - ); - }; }, }, { @@ -232,25 +223,6 @@ export default function configureCoreTaskFactory( ))); }, }, - { - title: 'Set initial mock time', - task: async () => { - // Set initial mock time from the last block - const { result: bestBlockHash } = await ctx.seedRpcClient.getBestBlockHash(); - const { result: bestBlock } = await ctx.seedRpcClient.getBlock(bestBlockHash); - - await ctx.bumpMockTime(bestBlock.time); - - // Sync nodes - await ctx.bumpMockTime(); - - await generateBlocks( - ctx.seedCoreService, - 1, - NETWORK_LOCAL, - ); - }, - }, { title: 'Wait for nodes to have the same height', task: () => waitForNodesToHaveTheSameHeight( diff --git a/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js index 49fbbd47379..a7036cbacfb 100644 --- a/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js @@ -50,8 +50,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { // move forward to next DKG const blocksUntilNextDKG = 24 - (bestBlockHeight % 24); if (blocksUntilNextDKG !== 0) { - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, blocksUntilNextDKG, @@ -82,7 +80,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { await waitForQuorumConnections( ctx.masternodeRpcClients, ctx.expectedConnections, - ctx.bumpMockTime, ); const { result: sporks } = await ctx.seedRpcClient.spork('show'); @@ -91,12 +88,9 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { if (isSpork21Active) { await waitForMasternodeProbes( ctx.masternodeRpcClients, - ctx.bumpMockTime, ); } - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 2, @@ -119,8 +113,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { ctx.expectedMembers, ); - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 2, @@ -145,8 +137,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { ctx.expectedComplaints, ); - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 2, @@ -171,8 +161,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { ctx.expectedJustifications, ); - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 2, @@ -197,8 +185,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { ctx.expectedCommitments, ); - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 2, @@ -232,8 +218,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { { title: 'Mining final commitment', task: async (ctx, task) => { - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 1, @@ -246,8 +230,6 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { while (!testPlatformQuorumEnabled) { await wait(300); - await ctx.bumpMockTime(); - await generateBlocks( ctx.seedCoreService, 1, diff --git a/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js index 242f65582ad..270bcda5bb6 100644 --- a/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/setupLocalPresetTaskFactory.js @@ -143,13 +143,11 @@ export default function setupLocalPresetTaskFactory( config.set('core.log.debug.enabled', true); } - // Although not all nodes are miners, all nodes should be aware of - // the miner interval to be able to sync mocked time - config.set('core.miner.interval', ctx.minerInterval); - config.set('dashmate.helper.api.port', config.get('dashmate.helper.api.port') + (i * 100)); if (config.getName() === 'local_seed') { + config.set('core.miner.interval', ctx.minerInterval); + config.set('description', 'seed node for local network'); config.set('core.masternode.enable', false); diff --git a/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js b/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js index eae01bd49e4..53b6762ee1e 100644 --- a/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/startGroupNodesTaskFactory.js @@ -82,46 +82,6 @@ export default function startGroupNodesTaskFactory( return new Listr(tasks, { concurrent: true }); }, }, - { - title: 'Mock core node time', - enabled: () => minerConfig && minerConfig.get('network') === NETWORK_LOCAL, - task: async () => { - // TASK RATIONALE: - // During DKG sessions, nodes can make only 1 quorum request per 10 minutes. - // If mocktime is not adjusted, quorums will start failing to form after some time. - const minerInterval = minerConfig.get('core.miner.interval'); - // 2.5 minutes - mimics the behaviour of the real network - const secondsToAdd = 150; - - const tasks = configGroup.map((config) => ({ - title: `Adjust ${config.getName()} mock time`, - task: async () => { - /* eslint-disable no-useless-escape */ - await dockerCompose.execCommand( - config, - 'core', - [ - 'bash', - '-c', - ` - response=\$(dash-cli getblockchaininfo); - mocktime=\$(echo \${response} | grep -o -E '\"mediantime\"\: [0-9]+' | cut -d ' ' -f2); - while true; do - mocktime=\$((mocktime + ${secondsToAdd})); - dash-cli setmocktime \$mocktime; - sleep ${minerInterval}; - done - `, - ], - ['--detach'], - ); - /* eslint-enable no-useless-escape */ - }, - })); - - return new Listr(tasks, { concurrent: true }); - }, - }, { title: 'Start a miner', enabled: () => minerConfig && minerConfig.get('network') === NETWORK_LOCAL, diff --git a/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js b/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js index e57101c96b3..1d3de2707c0 100644 --- a/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/stopNodeTaskFactory.js @@ -67,23 +67,6 @@ export default function stopNodeTaskFactory( host: await getConnectionHost(config, 'core', 'core.rpc.host'), })), }, - { - title: 'Save core node time', - enabled: () => config.get('group') === 'local', - skip: (ctx) => ctx.isForce, - task: async () => { - const rpcClient = createRpcClient({ - port: config.get('core.rpc.port'), - user: 'dashmate', - pass: config.get('core.rpc.users.dashmate.password'), - host: await getConnectionHost(config, 'core', 'core.rpc.host'), - }); - - const { result: { mediantime } } = await rpcClient.getBlockchainInfo(); - - config.set('core.miner.mediantime', mediantime); - }, - }, { title: `Stopping ${config.getName()} node`, task: async (ctx) => { diff --git a/packages/dashmate/templates/core/dash.conf.dot b/packages/dashmate/templates/core/dash.conf.dot index 78b71b095a1..5e5729de132 100644 --- a/packages/dashmate/templates/core/dash.conf.dot +++ b/packages/dashmate/templates/core/dash.conf.dot @@ -95,7 +95,6 @@ regtest=1 testactivationheight=mn_rr@1000 {{? it.core.spork.address}}sporkaddr={{=it.core.spork.address}}{{?}} {{? it.core.spork.privateKey}}sporkkey={{=it.core.spork.privateKey}}{{?}} -{{? it.core.miner.mediantime}}mocktime={{=it.core.miner.mediantime}}{{?}} llmqtestinstantsenddip0024=llmq_test_instantsend {{?? it.network === 'devnet'}} diff --git a/packages/dashpay-contract/Cargo.toml b/packages/dashpay-contract/Cargo.toml index cd693a64538..2ce75ff3744 100644 --- a/packages/dashpay-contract/Cargo.toml +++ b/packages/dashpay-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dashpay-contract" description = "DashPay data contract schema and tools" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/dashpay-contract/package.json b/packages/dashpay-contract/package.json index 62003582901..23edcde9785 100644 --- a/packages/dashpay-contract/package.json +++ b/packages/dashpay-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dashpay-contract", - "version": "1.7.0", + "version": "1.8.0", "description": "Reference contract of the DashPay DPA on Dash Evolution", "scripts": { "lint": "eslint .", diff --git a/packages/data-contracts/Cargo.toml b/packages/data-contracts/Cargo.toml index 5f8e3a624e4..c226a1fdf09 100644 --- a/packages/data-contracts/Cargo.toml +++ b/packages/data-contracts/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "data-contracts" description = "Dash Platform system data contracts" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/dpns-contract/Cargo.toml b/packages/dpns-contract/Cargo.toml index 144be65f29d..1cd1af6a603 100644 --- a/packages/dpns-contract/Cargo.toml +++ b/packages/dpns-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dpns-contract" description = "DPNS data contract schema and tools" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/dpns-contract/package.json b/packages/dpns-contract/package.json index b2892b39c48..8dd27f9ec56 100644 --- a/packages/dpns-contract/package.json +++ b/packages/dpns-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dpns-contract", - "version": "1.7.0", + "version": "1.8.0", "description": "A contract and helper scripts for DPNS DApp", "scripts": { "lint": "eslint .", diff --git a/packages/feature-flags-contract/Cargo.toml b/packages/feature-flags-contract/Cargo.toml index 9110fbbc65e..a9828c88ba2 100644 --- a/packages/feature-flags-contract/Cargo.toml +++ b/packages/feature-flags-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "feature-flags-contract" description = "Feature flags data contract schema and tools" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/feature-flags-contract/package.json b/packages/feature-flags-contract/package.json index f7bb0f39267..31d66de8150 100644 --- a/packages/feature-flags-contract/package.json +++ b/packages/feature-flags-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/feature-flags-contract", - "version": "1.7.0", + "version": "1.8.0", "description": "Data Contract to store Dash Platform feature flags", "scripts": { "build": "", diff --git a/packages/js-dapi-client/package.json b/packages/js-dapi-client/package.json index a5a5ffd8cfe..6a77fb52223 100644 --- a/packages/js-dapi-client/package.json +++ b/packages/js-dapi-client/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/dapi-client", - "version": "1.7.0", + "version": "1.8.0", "description": "Client library used to access Dash DAPI endpoints", "main": "lib/index.js", "contributors": [ diff --git a/packages/js-dash-sdk/package.json b/packages/js-dash-sdk/package.json index 77c0634b39a..77e085fb9cb 100644 --- a/packages/js-dash-sdk/package.json +++ b/packages/js-dash-sdk/package.json @@ -1,6 +1,6 @@ { "name": "dash", - "version": "4.7.0", + "version": "4.8.0", "description": "Dash library for JavaScript/TypeScript ecosystem (Wallet, DAPI, Primitives, BLS, ...)", "main": "build/index.js", "unpkg": "dist/dash.min.js", diff --git a/packages/js-grpc-common/package.json b/packages/js-grpc-common/package.json index 9119272974e..5f05d07dc70 100644 --- a/packages/js-grpc-common/package.json +++ b/packages/js-grpc-common/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/grpc-common", - "version": "1.7.0", + "version": "1.8.0", "description": "Common GRPC library", "main": "index.js", "scripts": { diff --git a/packages/masternode-reward-shares-contract/Cargo.toml b/packages/masternode-reward-shares-contract/Cargo.toml index 317e1d21d6e..760b45e4c36 100644 --- a/packages/masternode-reward-shares-contract/Cargo.toml +++ b/packages/masternode-reward-shares-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "masternode-reward-shares-contract" description = "Masternode reward shares data contract schema and tools" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/masternode-reward-shares-contract/package.json b/packages/masternode-reward-shares-contract/package.json index cbf2736ca9e..f88c304bec1 100644 --- a/packages/masternode-reward-shares-contract/package.json +++ b/packages/masternode-reward-shares-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/masternode-reward-shares-contract", - "version": "1.7.0", + "version": "1.8.0", "description": "A contract and helper scripts for reward sharing", "scripts": { "lint": "eslint .", diff --git a/packages/platform-test-suite/package.json b/packages/platform-test-suite/package.json index 895af1ea58c..26ee6056c45 100644 --- a/packages/platform-test-suite/package.json +++ b/packages/platform-test-suite/package.json @@ -1,7 +1,7 @@ { "name": "@dashevo/platform-test-suite", "private": true, - "version": "1.7.0", + "version": "1.8.0", "description": "Dash Network end-to-end tests", "scripts": { "test": "yarn exec bin/test.sh", diff --git a/packages/rs-dapi-client/Cargo.toml b/packages/rs-dapi-client/Cargo.toml index c6f32b443df..f48715b6dd6 100644 --- a/packages/rs-dapi-client/Cargo.toml +++ b/packages/rs-dapi-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rs-dapi-client" -version = "1.7.0" +version = "1.8.0" edition = "2021" [features] diff --git a/packages/rs-dapi-client/src/dapi_client.rs b/packages/rs-dapi-client/src/dapi_client.rs index ebca641f401..126d820e1ca 100644 --- a/packages/rs-dapi-client/src/dapi_client.rs +++ b/packages/rs-dapi-client/src/dapi_client.rs @@ -3,6 +3,7 @@ use backon::{ConstantBuilder, Retryable}; use dapi_grpc::mock::Mockable; use dapi_grpc::tonic::async_trait; +use dapi_grpc::tonic::transport::Certificate; use std::fmt::{Debug, Display}; use std::sync::atomic::AtomicUsize; use std::sync::Arc; @@ -76,6 +77,8 @@ pub struct DapiClient { address_list: AddressList, settings: RequestSettings, pool: ConnectionPool, + /// Certificate Authority certificate to use for verifying the server's certificate. + pub ca_certificate: Option, #[cfg(feature = "dump")] pub(crate) dump_dir: Option, } @@ -92,9 +95,24 @@ impl DapiClient { pool: ConnectionPool::new(address_count), #[cfg(feature = "dump")] dump_dir: None, + ca_certificate: None, } } + /// Set CA certificate to use when verifying the server's certificate. + /// + /// # Arguments + /// + /// * `pem_ca_cert` - CA certificate in PEM format. + /// + /// # Returns + /// [DapiClient] with CA certificate set. + pub fn with_ca_certificate(mut self, ca_cert: Certificate) -> Self { + self.ca_certificate = Some(ca_cert); + + self + } + /// Return the [DapiClient] address list. pub fn address_list(&self) -> &AddressList { &self.address_list @@ -182,7 +200,8 @@ impl DapiRequestExecutor for DapiClient { .settings .override_by(R::SETTINGS_OVERRIDES) .override_by(settings) - .finalize(); + .finalize() + .with_ca_certificate(self.ca_certificate.clone()); // Setup retry policy: let retry_settings = ConstantBuilder::default() @@ -198,6 +217,9 @@ impl DapiRequestExecutor for DapiClient { let retries_counter_arc = Arc::new(AtomicUsize::new(0)); let retries_counter_arc_ref = &retries_counter_arc; + // We need reference so that the closure is FnMut + let applied_settings_ref = &applied_settings; + // Setup DAPI request execution routine future. It's a closure that will be called // more once to build new future on each retry. let routine = move || { @@ -212,7 +234,7 @@ impl DapiRequestExecutor for DapiClient { let _span = tracing::trace_span!( "execute request", address = ?address_result, - settings = ?applied_settings, + settings = ?applied_settings_ref, method = request.method_name(), ) .entered(); @@ -242,7 +264,7 @@ impl DapiRequestExecutor for DapiClient { let mut transport_client = R::Client::with_uri_and_settings( address.uri().clone(), - &applied_settings, + applied_settings_ref, &pool, ) .map_err(|error| ExecutionError { @@ -252,7 +274,7 @@ impl DapiRequestExecutor for DapiClient { })?; let result = transport_request - .execute_transport(&mut transport_client, &applied_settings) + .execute_transport(&mut transport_client, applied_settings_ref) .await .map_err(DapiClientError::Transport); @@ -281,7 +303,7 @@ impl DapiRequestExecutor for DapiClient { update_address_ban_status::( &self.address_list, &execution_result, - &applied_settings, + applied_settings_ref, ); execution_result diff --git a/packages/rs-dapi-client/src/request_settings.rs b/packages/rs-dapi-client/src/request_settings.rs index 9ad08e88614..df89112322b 100644 --- a/packages/rs-dapi-client/src/request_settings.rs +++ b/packages/rs-dapi-client/src/request_settings.rs @@ -1,5 +1,6 @@ //! DAPI client request settings processing. +use dapi_grpc::tonic::transport::Certificate; use std::time::Duration; /// Default low-level client timeout @@ -64,12 +65,13 @@ impl RequestSettings { ban_failed_address: self .ban_failed_address .unwrap_or(DEFAULT_BAN_FAILED_ADDRESS), + ca_certificate: None, } } } /// DAPI settings ready to use. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct AppliedRequestSettings { /// Timeout for establishing a connection. pub connect_timeout: Option, @@ -79,4 +81,15 @@ pub struct AppliedRequestSettings { pub retries: usize, /// Ban DAPI address if node not responded or responded with error. pub ban_failed_address: bool, + /// Certificate Authority certificate to use for verifying the server's certificate. + pub ca_certificate: Option, +} +impl AppliedRequestSettings { + /// Use provided CA certificate for verifying the server's certificate. + /// + /// If set to None, the system's default CA certificates will be used. + pub fn with_ca_certificate(mut self, ca_cert: Option) -> Self { + self.ca_certificate = ca_cert; + self + } } diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 62a75904064..77b98acf812 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -8,7 +8,7 @@ use crate::{request_settings::AppliedRequestSettings, RequestSettings}; use dapi_grpc::core::v0::core_client::CoreClient; use dapi_grpc::core::v0::{self as core_proto}; use dapi_grpc::platform::v0::{self as platform_proto, platform_client::PlatformClient}; -use dapi_grpc::tonic::transport::{ClientTlsConfig, Uri}; +use dapi_grpc::tonic::transport::{Certificate, ClientTlsConfig, Uri}; use dapi_grpc::tonic::Streaming; use dapi_grpc::tonic::{transport::Channel, IntoRequest}; use futures::{future::BoxFuture, FutureExt, TryFutureExt}; @@ -22,19 +22,29 @@ fn create_channel( uri: Uri, settings: Option<&AppliedRequestSettings>, ) -> Result { - let mut builder = Channel::builder(uri).tls_config( - ClientTlsConfig::new() - .with_native_roots() - .with_webpki_roots() - .assume_http2(true), - )?; + let host = uri.host().expect("Failed to get host from URI").to_string(); + + let mut builder = Channel::builder(uri); + let mut tls_config = ClientTlsConfig::new() + .with_native_roots() + .with_webpki_roots() + .assume_http2(true); if let Some(settings) = settings { if let Some(timeout) = settings.connect_timeout { builder = builder.connect_timeout(timeout); } + + if let Some(pem) = settings.ca_certificate.as_ref() { + let cert = Certificate::from_pem(pem); + tls_config = tls_config.ca_certificate(cert).domain_name(host); + }; } + builder = builder + .tls_config(tls_config) + .expect("Failed to set TLS config"); + Ok(builder.connect_lazy()) } @@ -256,8 +266,10 @@ impl_transport_request_grpc!( platform_proto::WaitForStateTransitionResultResponse, PlatformGrpcClient, RequestSettings { - timeout: Some(Duration::from_secs(120)), - ..RequestSettings::default() + timeout: Some(Duration::from_secs(80)), + retries: Some(0), + ban_failed_address: None, + connect_timeout: None, }, wait_for_state_transition_result ); @@ -487,7 +499,9 @@ impl_transport_request_grpc!( CoreGrpcClient, RequestSettings { timeout: Some(STREAMING_TIMEOUT), - ..RequestSettings::default() + ban_failed_address: None, + connect_timeout: None, + retries: None, }, subscribe_to_transactions_with_proofs ); diff --git a/packages/rs-dapi-grpc-macros/Cargo.toml b/packages/rs-dapi-grpc-macros/Cargo.toml index 90f280a6ed0..32c2bddba39 100644 --- a/packages/rs-dapi-grpc-macros/Cargo.toml +++ b/packages/rs-dapi-grpc-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dapi-grpc-macros" -version = "1.7.0" +version = "1.8.0" edition = "2021" description = "Macros used by dapi-grpc. Internal use only." diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index f526a76c8a1..ec555a11d18 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dpp" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true authors = [ @@ -28,7 +28,7 @@ dashcore = { git = "https://github.com/dashpay/rust-dashcore", features = [ "rand", "signer", "serde", -], default-features = false, tag = "0.34.0" } +], default-features = false, tag = "v0.35.0" } env_logger = { version = "0.11" } getrandom = { version = "0.2", features = ["js"] } hex = { version = "0.4" } diff --git a/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/mod.rs b/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/mod.rs index b1cd0a477db..997bd422621 100644 --- a/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/mod.rs +++ b/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/mod.rs @@ -4,6 +4,7 @@ use crate::ProtocolError; use platform_version::version::PlatformVersion; mod v0; +mod v1; pub fn daily_withdrawal_limit( total_credits_in_platform: Credits, @@ -11,6 +12,7 @@ pub fn daily_withdrawal_limit( ) -> Result { match platform_version.dpp.methods.daily_withdrawal_limit { 0 => Ok(daily_withdrawal_limit_v0(total_credits_in_platform)), + 1 => Ok(v1::daily_withdrawal_limit_v1()), v => Err(ProtocolError::UnknownVersionError(format!( "Unknown daily_withdrawal_limit version {v}" ))), diff --git a/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/v1/mod.rs b/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/v1/mod.rs new file mode 100644 index 00000000000..56112338a6d --- /dev/null +++ b/packages/rs-dpp/src/withdrawal/daily_withdrawal_limit/v1/mod.rs @@ -0,0 +1,8 @@ +use crate::fee::Credits; + +/// Set constant withdrawal daily limit to 2000 Dash +/// that corresponds to the limit in Core v22. +pub const fn daily_withdrawal_limit_v1() -> Credits { + // 2000 Dash + 200_000_000_000_000 +} diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 71a4dc43996..a082a59a8f0 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "drive-abci" -version = "1.7.0" +version = "1.8.0" authors = [ "Samuel Westrich ", "Ivan Shumkov ", @@ -28,7 +28,7 @@ rand = "0.8.5" tempfile = "3.3.0" hex = "0.4.3" indexmap = { version = "2.2.6", features = ["serde"] } -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.15.13" } +dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.16.0" } dpp = { path = "../rs-dpp", features = ["abci"] } simple-signer = { path = "../simple-signer" } rust_decimal = "1.2.5" @@ -99,7 +99,7 @@ assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config"] } # For tests of grovedb verify -rocksdb = { version = "0.22.0" } +rocksdb = { version = "0.23.0" } integer-encoding = { version = "4.0.0" } [features] diff --git a/packages/rs-drive-abci/src/abci/handler/check_tx.rs b/packages/rs-drive-abci/src/abci/handler/check_tx.rs index bcad2ba2b42..f087bcb5d84 100644 --- a/packages/rs-drive-abci/src/abci/handler/check_tx.rs +++ b/packages/rs-drive-abci/src/abci/handler/check_tx.rs @@ -151,10 +151,11 @@ where let handler_error = HandlerError::Internal(error.to_string()); if tracing::enabled!(tracing::Level::ERROR) { - let st_hash = hex::encode(hash_single(tx)); + let st_hash = hex::encode(hash_single(&tx)); tracing::error!( ?error, + st = hex::encode(tx), st_hash, check_tx_mode = r#type, "Failed to check state transition ({}): {}", 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 4cef4a48bca..6eb4fd82bb3 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 @@ -270,6 +270,10 @@ where })?; // This is a system error // Rebroadcast expired withdrawals if they exist + // We do that before we mark withdrawals as expired + // to rebroadcast them on the next block but not the same + // one + // TODO: It must be also only on core height change self.rebroadcast_expired_withdrawal_documents( &block_info, last_committed_platform_state, 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 d36250ea3e7..27a10ad10c7 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 @@ -1,3 +1,4 @@ +use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; @@ -5,9 +6,13 @@ use crate::platform_types::platform_state::PlatformState; use dpp::block::block_info::BlockInfo; use dpp::dashcore::hashes::Hash; use dpp::data_contracts::SystemDataContract; +use dpp::fee::Credits; +use dpp::platform_value::Identifier; +use dpp::serialization::PlatformDeserializable; 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::identity::key::fetch::{ IdentityKeysRequest, KeyIDIdentityPublicKeyPairBTreeMap, KeyRequestType, }; @@ -15,7 +20,15 @@ use drive::drive::identity::withdrawals::paths::{ get_withdrawal_root_path, WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, }; -use drive::grovedb::{Element, Transaction}; +use drive::drive::prefunded_specialized_balances::{ + prefunded_specialized_balances_for_voting_path, + prefunded_specialized_balances_for_voting_path_vec, +}; +use drive::drive::votes::paths::vote_end_date_queries_tree_path_vec; +use drive::grovedb::{Element, PathQuery, Query, QueryItem, SizedQuery, Transaction}; +use drive::query::QueryResultType; +use std::collections::HashSet; +use std::ops::RangeFull; impl Platform { /// Executes protocol-specific events on the first block after a protocol version change. @@ -58,6 +71,20 @@ impl Platform { self.transition_to_version_6(block_info, transaction, platform_version)?; } + if previous_protocol_version < 8 && platform_version.protocol_version >= 8 { + self.transition_to_version_8(block_info, transaction, platform_version) + .or_else(|e| { + tracing::error!( + error = ?e, + "Error while transitioning to version 8: {e}" + ); + + // We ignore this transition errors because it's not changing the state stucture + // and not critical for the system + Ok::<(), Error>(()) + })?; + } + Ok(()) } @@ -86,6 +113,131 @@ impl Platform { Ok(()) } + /// When transitioning to version 8 we need to empty some specialized balances + fn transition_to_version_8( + &self, + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + // Let's start by getting all the specialized balances that exist + let path_holding_specialized_balances = + prefunded_specialized_balances_for_voting_path_vec(); + let path_query = PathQuery::new_single_query_item( + path_holding_specialized_balances, + QueryItem::RangeFull(RangeFull), + ); + let all_specialized_balances_still_around: HashSet<_> = self + .drive + .grove_get_path_query( + &path_query, + Some(transaction), + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )? + .0 + .to_keys() + .into_iter() + .map(Identifier::try_from) + .collect::, dpp::platform_value::Error>>()?; + + let path = vote_end_date_queries_tree_path_vec(); + + let mut query = Query::new_with_direction(true); + + query.insert_all(); + + let mut sub_query = Query::new(); + + sub_query.insert_all(); + + query.default_subquery_branch.subquery = Some(sub_query.into()); + + let current_votes_path_query = PathQuery { + path, + query: SizedQuery { + query, + limit: Some(30000), //Just a high number that shouldn't break the system + offset: None, + }, + }; + + let (query_result_elements, _) = self.drive.grove_get_path_query( + ¤t_votes_path_query, + Some(transaction), + QueryResultType::QueryElementResultType, + &mut vec![], + &platform_version.drive, + )?; + + let active_specialized_balances = query_result_elements + .to_elements() + .into_iter() + .map(|element| { + let contested_document_resource_vote_poll_bytes = element + .into_item_bytes() + .map_err(drive::error::Error::GroveDB)?; + let vote_poll = + VotePoll::deserialize_from_bytes(&contested_document_resource_vote_poll_bytes)?; + match vote_poll { + VotePoll::ContestedDocumentResourceVotePoll(contested) => { + contested.specialized_balance_id().map_err(Error::Protocol) + } + } + }) + .collect::, Error>>()?; + + // let's get the non-active ones + let non_active_specialized_balances = + all_specialized_balances_still_around.difference(&active_specialized_balances); + + let mut total_credits_to_add_to_processing: Credits = 0; + + let mut operations = vec![]; + + for specialized_balance_id in non_active_specialized_balances { + let (credits, mut empty_specialized_balance_operation) = + self.drive.empty_prefunded_specialized_balance_operations( + *specialized_balance_id, + false, + &mut None, + Some(transaction), + platform_version, + )?; + operations.append(&mut empty_specialized_balance_operation); + total_credits_to_add_to_processing = total_credits_to_add_to_processing + .checked_add(credits) + .ok_or(Error::Execution(ExecutionError::Overflow( + "Credits from specialized balances are overflowing", + )))?; + } + + if total_credits_to_add_to_processing > 0 { + operations.push( + self.drive + .add_epoch_processing_credits_for_distribution_operation( + &block_info.epoch, + total_credits_to_add_to_processing, + Some(transaction), + platform_version, + )?, + ); + } + + if !operations.is_empty() { + self.drive.apply_batch_low_level_drive_operations( + None, + Some(transaction), + operations, + &mut vec![], + &platform_version.drive, + )?; + } + + 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/voting/check_for_ended_vote_polls/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/voting/check_for_ended_vote_polls/v0/mod.rs index 426888de5da..a7175c4c7db 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/voting/check_for_ended_vote_polls/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/voting/check_for_ended_vote_polls/v0/mod.rs @@ -310,6 +310,7 @@ where // This means removing it and also removing all current votes if !vote_polls_with_info.is_empty() { self.clean_up_after_vote_polls_end( + block_info, &vote_polls_with_info, clean_up_testnet_corrupted_reference_issue, transaction, diff --git a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/mod.rs index 1c13190a5a4..d3cdd55fa2c 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/mod.rs @@ -2,6 +2,7 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::platform::Platform; use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::prelude::TimestampMillis; use dpp::version::PlatformVersion; @@ -11,6 +12,7 @@ use drive::grovedb::TransactionArg; use std::collections::BTreeMap; mod v0; +mod v1; impl Platform where @@ -19,6 +21,7 @@ where /// Checks for ended vote polls pub(in crate::execution) fn clean_up_after_contested_resources_vote_polls_end( &self, + block_info: &BlockInfo, vote_polls: Vec<( &ContestedDocumentResourceVotePollWithContractInfo, &TimestampMillis, @@ -40,9 +43,16 @@ where transaction, platform_version, ), + 1 => self.clean_up_after_contested_resources_vote_polls_end_v1( + block_info, + vote_polls, + clean_up_testnet_corrupted_reference_issue, + transaction, + platform_version, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "clean_up_after_contested_resources_vote_polls_end".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } diff --git a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v0/mod.rs index f444ed1e61f..3dc1777acfd 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v0/mod.rs @@ -8,6 +8,7 @@ use dpp::version::PlatformVersion; use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; use dpp::ProtocolError; use drive::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo; +use drive::fees::op::LowLevelDriveOperation; use drive::grovedb::TransactionArg; use std::collections::BTreeMap; @@ -28,12 +29,43 @@ where transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result<(), Error> { + let operations = self.clean_up_after_contested_resources_vote_polls_end_operations_v0( + vote_polls.as_slice(), + clean_up_testnet_corrupted_reference_issue, + transaction, + platform_version, + )?; + if !operations.is_empty() { + self.drive.apply_batch_low_level_drive_operations( + None, + transaction, + operations, + &mut vec![], + &platform_version.drive, + )?; + } + + Ok(()) + } + /// Checks for ended vote polls + #[inline(always)] + pub(super) fn clean_up_after_contested_resources_vote_polls_end_operations_v0( + &self, + vote_polls: &[( + &ContestedDocumentResourceVotePollWithContractInfo, + &TimestampMillis, + &BTreeMap>, + )], + clean_up_testnet_corrupted_reference_issue: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { let mut operations = vec![]; // We remove the end date query self.drive .remove_contested_resource_vote_poll_end_date_query_operations( - vote_polls.as_slice(), + vote_polls, &mut operations, transaction, platform_version, @@ -42,7 +74,7 @@ where // We remove the votes from under the contenders votes received self.drive .remove_contested_resource_vote_poll_votes_operations( - vote_polls.as_slice(), + vote_polls, true, &mut operations, transaction, @@ -52,7 +84,7 @@ where // We remove the documents that contenders have self.drive .remove_contested_resource_vote_poll_documents_operations( - vote_polls.as_slice(), + vote_polls, clean_up_testnet_corrupted_reference_issue, &mut operations, transaction, @@ -62,7 +94,7 @@ where // We remove the contenders self.drive .remove_contested_resource_vote_poll_contenders_operations( - vote_polls.as_slice(), + vote_polls, &mut operations, transaction, platform_version, @@ -81,7 +113,7 @@ where let mut identity_to_vote_ids_map: BTreeMap<&Identifier, Vec<&Identifier>> = BTreeMap::new(); - for (vote_poll, _, voters_for_contender) in &vote_polls { + for (vote_poll, _, voters_for_contender) in vote_polls { let vote_id = vote_poll_ids .iter() .find_map(|(vp, vid)| if vp == vote_poll { Some(vid) } else { None }) @@ -113,7 +145,7 @@ where if clean_up_testnet_corrupted_reference_issue { self.drive.remove_contested_resource_info_operations( - vote_polls.as_slice(), + vote_polls, &mut operations, transaction, platform_version, @@ -121,23 +153,13 @@ where // We remove the last index self.drive .remove_contested_resource_top_level_index_operations( - vote_polls.as_slice(), + vote_polls, &mut operations, transaction, platform_version, )?; } - if !operations.is_empty() { - self.drive.apply_batch_low_level_drive_operations( - None, - transaction, - operations, - &mut vec![], - &platform_version.drive, - )?; - } - - Ok(()) + Ok(operations) } } diff --git a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v1/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v1/mod.rs new file mode 100644 index 00000000000..9fd22acf087 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_contested_resources_vote_polls_end/v1/mod.rs @@ -0,0 +1,88 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::prelude::TimestampMillis; +use dpp::version::PlatformVersion; +use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice; +use drive::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo; +use drive::grovedb::TransactionArg; +use std::collections::BTreeMap; + +impl Platform +where + C: CoreRPCLike, +{ + /// Checks for ended vote polls + #[inline(always)] + pub(super) fn clean_up_after_contested_resources_vote_polls_end_v1( + &self, + block_info: &BlockInfo, + vote_polls: Vec<( + &ContestedDocumentResourceVotePollWithContractInfo, + &TimestampMillis, + &BTreeMap>, + )>, + clean_up_testnet_corrupted_reference_issue: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let mut operations = self.clean_up_after_contested_resources_vote_polls_end_operations_v0( + vote_polls.as_slice(), + clean_up_testnet_corrupted_reference_issue, + transaction, + platform_version, + )?; + + // We also need to clean out the specialized balances + + let mut total_credits_to_add_to_processing: Credits = 0; + + for specialized_balance_id in vote_polls + .iter() + .map(|(vote_poll, _, _)| vote_poll.specialized_balance_id()) + { + let (credits, mut empty_specialized_balance_operation) = + self.drive.empty_prefunded_specialized_balance_operations( + specialized_balance_id?, + false, + &mut None, + transaction, + platform_version, + )?; + operations.append(&mut empty_specialized_balance_operation); + total_credits_to_add_to_processing = total_credits_to_add_to_processing + .checked_add(credits) + .ok_or(Error::Execution(ExecutionError::Overflow( + "Credits from specialized balances are overflowing", + )))?; + } + + if total_credits_to_add_to_processing > 0 { + operations.push( + self.drive + .add_epoch_processing_credits_for_distribution_operation( + &block_info.epoch, + total_credits_to_add_to_processing, + transaction, + platform_version, + )?, + ); + } + + if !operations.is_empty() { + self.drive.apply_batch_low_level_drive_operations( + None, + transaction, + operations, + &mut vec![], + &platform_version.drive, + )?; + } + + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/mod.rs index 2852effd323..6580b030998 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/mod.rs @@ -2,6 +2,7 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::platform::Platform; use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; use dpp::prelude::TimestampMillis; use dpp::version::PlatformVersion; use drive::drive::votes::resolved::vote_polls::ResolvedVotePollWithVotes; @@ -17,6 +18,7 @@ where /// Checks for ended vote polls pub(in crate::execution) fn clean_up_after_vote_polls_end( &self, + block_info: &BlockInfo, vote_polls: &BTreeMap>, clean_up_testnet_corrupted_reference_issue: bool, transaction: TransactionArg, @@ -29,6 +31,7 @@ where .clean_up_after_vote_poll_end { 0 => self.clean_up_after_vote_polls_end_v0( + block_info, vote_polls, clean_up_testnet_corrupted_reference_issue, transaction, diff --git a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/v0/mod.rs index a5b0d75a3b5..81d8b84157b 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/voting/clean_up_after_vote_polls_end/v0/mod.rs @@ -1,6 +1,7 @@ use crate::error::Error; use crate::platform_types::platform::Platform; use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; use dpp::identifier::Identifier; use dpp::prelude::TimestampMillis; use dpp::version::PlatformVersion; @@ -18,6 +19,7 @@ where #[inline(always)] pub(super) fn clean_up_after_vote_polls_end_v0( &self, + block_info: &BlockInfo, vote_polls: &BTreeMap>, clean_up_testnet_corrupted_reference_issue: bool, transaction: TransactionArg, @@ -44,6 +46,7 @@ where if !contested_polls.is_empty() { // Call the function to clean up contested document resource vote polls self.clean_up_after_contested_resources_vote_polls_end( + block_info, contested_polls, clean_up_testnet_corrupted_reference_issue, transaction, diff --git a/packages/rs-drive-abci/src/execution/platform_events/withdrawals/append_signatures_and_broadcast_withdrawal_transactions/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/withdrawals/append_signatures_and_broadcast_withdrawal_transactions/v0/mod.rs index 1f6cacbc2bf..c8f8dda8e5a 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/withdrawals/append_signatures_and_broadcast_withdrawal_transactions/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/withdrawals/append_signatures_and_broadcast_withdrawal_transactions/v0/mod.rs @@ -1,10 +1,7 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::platform_types::platform::Platform; -use crate::rpc::core::{ - CoreRPCLike, CORE_RPC_ERROR_ASSET_UNLOCK_EXPIRED, CORE_RPC_ERROR_ASSET_UNLOCK_NO_ACTIVE_QUORUM, - CORE_RPC_TX_ALREADY_IN_CHAIN, -}; +use crate::rpc::core::{CoreRPCLike, CORE_RPC_TX_ALREADY_IN_CHAIN}; use dashcore_rpc::jsonrpc; use dashcore_rpc::Error as CoreRPCError; use dpp::dashcore::bls_sig_utils::BLSSignature; @@ -18,6 +15,14 @@ use std::path::Path; use std::time::{SystemTime, UNIX_EPOCH}; use tenderdash_abci::proto::types::VoteExtension; +// This error is returned when Core can't find a quorum for the asset unlock transaction in Core 21 +const CORE_RPC_ERROR_ASSET_UNLOCK_NO_ACTIVE_QUORUM: &str = "bad-assetunlock-not-active-quorum"; + +// This error replaced the previous since Core 22 to make it more verbose +const CORE_RPC_ERROR_ASSET_UNLOCK_TOO_OLD_QUORUM: &str = "bad-assetunlock-too-old-quorum"; + +const CORE_RPC_ERROR_ASSET_UNLOCK_EXPIRED: &str = "bad-assetunlock-too-late"; + impl Platform where C: CoreRPCLike, @@ -90,7 +95,8 @@ where } Err(CoreRPCError::JsonRpc(jsonrpc::error::Error::Rpc(e))) if e.message == CORE_RPC_ERROR_ASSET_UNLOCK_NO_ACTIVE_QUORUM - || e.message == CORE_RPC_ERROR_ASSET_UNLOCK_EXPIRED => + || e.message == CORE_RPC_ERROR_ASSET_UNLOCK_EXPIRED + || e.message == CORE_RPC_ERROR_ASSET_UNLOCK_TOO_OLD_QUORUM => { tracing::debug!( tx_id = transaction.txid().to_string(), 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/documents_batch/mod.rs index 1cb7c26a62b..e5ee8b99199 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/documents_batch/mod.rs @@ -6448,6 +6448,7 @@ mod tests { mod nft_tests { use super::*; + use crate::test::helpers::fast_forward_to_block::fast_forward_to_block; #[test] fn test_document_set_price_on_document_without_ability_to_purchase() { let platform_version = PlatformVersion::latest(); @@ -7193,7 +7194,920 @@ mod tests { .expect("expected to get purchaser balance") .expect("expected that purchaser exists"); - // the buyer payed 0.1, but also storage and processing fees + // the buyer paid 0.1, but also storage and processing fees + assert_eq!(buyers_balance, dash_to_credits!(0.9) - 68691480); + } + + #[test] + fn test_document_set_price_and_purchase_different_epoch_documents_mutable() { + let platform_version = PlatformVersion::latest(); + let mut platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure(); + + let card_game_path = "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-documents-mutable.json"; + + // let's construct the grovedb structure for the card game data contract + let contract = json_document_to_contract(card_game_path, true, platform_version) + .expect("expected to get data contract"); + platform + .drive + .apply_contract( + &contract, + BlockInfo::default(), + true, + StorageFlags::optional_default_as_cow(), + None, + platform_version, + ) + .expect("expected to apply contract successfully"); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (purchaser, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(1.0)); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + assert_eq!(seller_balance, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &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_eq!(processing_result.valid_count(), 1); + + assert_eq!( + processing_result + .aggregated_fees() + .clone() + .into_balance_change(identity.id()) + .change(), + &BalanceChange::RemoveFromBalance { + required_removed_balance: 138159000, + desired_removed_balance: 141234660, + } + ); + + let original_creation_cost = 141234660; + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) - original_creation_cost + ); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveDocumentQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", purchaser.id()); + + let query_receiver_identity_documents = DriveDocumentQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + // now let's modify the document + + fast_forward_to_block(&platform, 500_000, 100, 3, 1, false); //next epoch + + document.set("description", "chopsticks".into()); + document.bump_revision(); + + let documents_batch_update_transition = + DocumentsBatchTransition::new_document_replacement_transition_from_document( + document.clone(), + card_document_type, + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition"); + + let documents_batch_update_serialized_transition = documents_batch_update_transition + .serialize_to_bytes() + .expect("expected documents batch serialized state transition"); + + let transaction = platform.drive.grove.start_transaction(); + + let platform_state = platform.state.load(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![documents_batch_update_serialized_transition.clone()], + &platform_state, + platform_state.last_block_info(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!( + processing_result.invalid_paid_count(), + 0, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!( + processing_result.invalid_unpaid_count(), + 0, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!( + processing_result.valid_count(), + 1, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!(processing_result.aggregated_fees().storage_fee, 378000); + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + None + ); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2717400); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) - original_creation_cost - 2717400 - 378000 + ); + + // now let's update price, but first go to next epoch + + fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 2, false); //next epoch + + document.bump_revision(); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 4, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!( + processing_result.invalid_paid_count(), + 0, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!( + processing_result.invalid_unpaid_count(), + 0, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!(processing_result.valid_count(), 1); + + assert_eq!(processing_result.aggregated_fees().storage_fee, 216000); // we added 8 bytes for the price + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + None + ); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2721160); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) + - original_creation_cost + - 2717400 + - 378000 + - 2721160 + - 216000 + ); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + // The sender document should have the desired price + + let mut document = query_sender_results.documents_owned().remove(0); + + let price: Credits = document + .properties() + .get_integer("$price") + .expect("expected to get back price"); + + assert_eq!(dash_to_credits!(0.1), price); + + // At this point we want to have the receiver purchase the document at the next epoch + + fast_forward_to_block(&platform, 1_700_000_000, 1200, 42, 3, false); //next epoch + + document.bump_revision(); + + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + purchaser.id(), + dash_to_credits!(0.1), //same price as requested + &recipient_key, + 1, // 1 because he's never done anything + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + assert_eq!( + processing_result.invalid_paid_count(), + 0, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!( + processing_result.invalid_unpaid_count(), + 0, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!( + processing_result.valid_count(), + 1, + "{:?}", + processing_result.execution_results() + ); + + assert_eq!(processing_result.aggregated_fees().storage_fee, 64611000); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 4345280); + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + Some(52987722) + ); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to have no documents, and the receiver to have 1 + assert_eq!(query_sender_results.documents().len(), 0); + + assert_eq!(query_receiver_results.documents().len(), 1); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.2) - original_creation_cost + 46955162 + ); + + let buyers_balance = platform + .drive + .fetch_identity_balance(purchaser.id().to_buffer(), None, platform_version) + .expect("expected to get purchaser balance") + .expect("expected that purchaser exists"); + + // the buyer paid 0.1, but also storage and processing fees + assert_eq!(buyers_balance, dash_to_credits!(0.9) - 68956280); + } + + #[test] + fn test_document_set_price_and_purchase_different_epoch() { + let platform_version = PlatformVersion::latest(); + let (mut platform, contract) = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_initial_state_structure() + .with_crypto_card_game_nft(TradeMode::DirectPurchase); + + let mut rng = StdRng::seed_from_u64(433); + + let platform_state = platform.state.load(); + + let (identity, signer, key) = setup_identity(&mut platform, 958, dash_to_credits!(0.1)); + + let (purchaser, recipient_signer, recipient_key) = + setup_identity(&mut platform, 450, dash_to_credits!(1.0)); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + assert_eq!(seller_balance, dash_to_credits!(0.1)); + + let card_document_type = contract + .document_type_for_name("card") + .expect("expected a profile document type"); + + assert!(!card_document_type.documents_mutable()); + + let entropy = Bytes32::random_with_rng(&mut rng); + + let mut document = card_document_type + .random_document_with_identifier_and_entropy( + &mut rng, + identity.id(), + entropy, + DocumentFieldFillType::DoNotFillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + platform_version, + ) + .expect("expected a random document"); + + document.set("attack", 4.into()); + document.set("defense", 7.into()); + + let documents_batch_create_transition = + DocumentsBatchTransition::new_document_creation_transition_from_document( + document.clone(), + card_document_type, + entropy.0, + &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_eq!(processing_result.valid_count(), 1); + + assert_eq!( + processing_result + .aggregated_fees() + .clone() + .into_balance_change(identity.id()) + .change(), + &BalanceChange::RemoveFromBalance { + required_removed_balance: 123579000, + desired_removed_balance: 126435860, + } + ); + + let original_creation_cost = 126435860; + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) - original_creation_cost + ); + + let sender_documents_sql_string = + format!("select * from card where $ownerId == '{}'", identity.id()); + + let query_sender_identity_documents = DriveDocumentQuery::from_sql_expr( + sender_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let receiver_documents_sql_string = + format!("select * from card where $ownerId == '{}'", purchaser.id()); + + let query_receiver_identity_documents = DriveDocumentQuery::from_sql_expr( + receiver_documents_sql_string.as_str(), + &contract, + Some(&platform.config.drive), + ) + .expect("expected document query"); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to have 1 document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + // now let's update price, but first go to next epoch + + fast_forward_to_block(&platform, 1_200_000_000, 900, 42, 1, false); //next epoch + + document.set_revision(Some(2)); + + let documents_batch_update_price_transition = + DocumentsBatchTransition::new_document_update_price_transition_from_document( + document.clone(), + card_document_type, + dash_to_credits!(0.1), + &key, + 3, + 0, + &signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the update price"); + + let documents_batch_transfer_serialized_transition = + documents_batch_update_price_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_transfer_serialized_transition.clone()], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + 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().storage_fee, 216000); // we added 8 bytes for the price + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + None + ); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 2473880); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.1) - original_creation_cost - 2689880 + ); + + let query_sender_results = platform + .drive + .query_documents( + query_sender_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents( + query_receiver_identity_documents.clone(), + None, + false, + None, + None, + ) + .expect("expected query result"); + + // We expect the sender to still have their document, and the receiver to have none + assert_eq!(query_sender_results.documents().len(), 1); + + assert_eq!(query_receiver_results.documents().len(), 0); + + // The sender document should have the desired price + + let mut document = query_sender_results.documents_owned().remove(0); + + let price: Credits = document + .properties() + .get_integer("$price") + .expect("expected to get back price"); + + assert_eq!(dash_to_credits!(0.1), price); + + // At this point we want to have the receiver purchase the document at the next epoch + + fast_forward_to_block(&platform, 1_700_000_000, 1200, 42, 2, false); //next epoch + + document.set_revision(Some(3)); + + let documents_batch_purchase_transition = + DocumentsBatchTransition::new_document_purchase_transition_from_document( + document.clone(), + card_document_type, + purchaser.id(), + dash_to_credits!(0.1), //same price as requested + &recipient_key, + 1, // 1 because he's never done anything + 0, + &recipient_signer, + platform_version, + None, + None, + None, + ) + .expect("expect to create documents batch transition for the purchase"); + + let documents_batch_purchase_serialized_transition = + documents_batch_purchase_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_purchase_serialized_transition], + &platform_state, + &BlockInfo::default_with_time(50000000), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + 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().storage_fee, 64611000); + + assert_eq!(processing_result.aggregated_fees().processing_fee, 4080480); + + assert_eq!( + processing_result + .aggregated_fees() + .fee_refunds + .calculate_refunds_amount_for_identity(identity.id()), + Some(22704503) + ); + + let query_sender_results = platform + .drive + .query_documents(query_sender_identity_documents, None, false, None, None) + .expect("expected query result"); + + let query_receiver_results = platform + .drive + .query_documents(query_receiver_identity_documents, None, false, None, None) + .expect("expected query result"); + + // We expect the sender to have no documents, and the receiver to have 1 + assert_eq!(query_sender_results.documents().len(), 0); + + assert_eq!(query_receiver_results.documents().len(), 1); + + let seller_balance = platform + .drive + .fetch_identity_balance(identity.id().to_buffer(), None, platform_version) + .expect("expected to get identity balance") + .expect("expected that identity exists"); + + // the seller should have received 0.1 and already had 0.1 minus the processing fee and storage fee + assert_eq!( + seller_balance, + dash_to_credits!(0.2) - original_creation_cost + 20014623 + ); + + let buyers_balance = platform + .drive + .fetch_identity_balance(purchaser.id().to_buffer(), None, platform_version) + .expect("expected to get purchaser balance") + .expect("expected that purchaser exists"); + + // the buyer paid 0.1, but also storage and processing fees assert_eq!(buyers_balance, dash_to_credits!(0.9) - 68691480); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/mod.rs index 216c68a1ecb..79818202cde 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/mod.rs @@ -2,6 +2,7 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::masternode_vote::nonce::v0::MasternodeVoteTransitionIdentityNonceV0; +use crate::execution::validation::state_transition::masternode_vote::nonce::v1::MasternodeVoteTransitionIdentityNonceV1; use crate::execution::validation::state_transition::processor::v0::StateTransitionNonceValidationV0; use crate::platform_types::platform::PlatformStateRef; use dpp::block::block_info::BlockInfo; @@ -11,6 +12,8 @@ use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; pub(crate) mod v0; +pub(crate) mod v1; + impl StateTransitionNonceValidationV0 for MasternodeVoteTransition { fn validate_nonces( &self, @@ -34,14 +37,21 @@ impl StateTransitionNonceValidationV0 for MasternodeVoteTransition { execution_context, platform_version, ), + Some(1) => self.validate_nonce_v1( + platform, + block_info, + tx, + execution_context, + platform_version, + ), Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "masternode vote transition: validate_nonces".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), None => Err(Error::Execution(ExecutionError::VersionNotActive { method: "masternode vote transition: validate_nonces".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], })), } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v0/mod.rs index bdb92a5a716..fd9ea2cc165 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v0/mod.rs @@ -14,6 +14,7 @@ use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; +use crate::execution::validation::state_transition::masternode_vote::nonce::v1::MasternodeVoteTransitionIdentityNonceV1; use crate::platform_types::platform::PlatformStateRef; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; @@ -39,6 +40,17 @@ impl MasternodeVoteTransitionIdentityNonceV0 for MasternodeVoteTransition { execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result { + // We are introducing this as an emergency hard fork activating at epoch 13. + if block_info.epoch.index >= 13 { + return self.validate_nonce_v1( + platform, + block_info, + tx, + execution_context, + platform_version, + ); + } + let revision_nonce = self.nonce(); if revision_nonce & MISSING_IDENTITY_REVISIONS_FILTER > 0 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v1/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v1/mod.rs new file mode 100644 index 00000000000..6fa254f7fbe --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/masternode_vote/nonce/v1/mod.rs @@ -0,0 +1,71 @@ +use crate::error::Error; +use dpp::block::block_info::BlockInfo; +use dpp::consensus::basic::document::NonceOutOfBoundsError; +use dpp::consensus::basic::BasicError; +use dpp::identity::identity_nonce::{ + validate_identity_nonce_update, validate_new_identity_nonce, MISSING_IDENTITY_REVISIONS_FILTER, +}; +use dpp::state_transition::masternode_vote_transition::accessors::MasternodeVoteTransitionAccessorsV0; +use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition; + +use dpp::validation::SimpleConsensusValidationResult; + +use crate::execution::types::execution_operation::ValidationOperation; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use crate::platform_types::platform::PlatformStateRef; +use dpp::version::PlatformVersion; +use drive::grovedb::TransactionArg; + +pub(in crate::execution::validation::state_transition::state_transitions) trait MasternodeVoteTransitionIdentityNonceV1 +{ + fn validate_nonce_v1( + &self, + platform: &PlatformStateRef, + block_info: &BlockInfo, + tx: TransactionArg, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl MasternodeVoteTransitionIdentityNonceV1 for MasternodeVoteTransition { + fn validate_nonce_v1( + &self, + platform: &PlatformStateRef, + block_info: &BlockInfo, + tx: TransactionArg, + execution_context: &mut StateTransitionExecutionContext, + platform_version: &PlatformVersion, + ) -> Result { + let revision_nonce = self.nonce(); + + if revision_nonce & MISSING_IDENTITY_REVISIONS_FILTER > 0 { + return Ok(SimpleConsensusValidationResult::new_with_error( + BasicError::NonceOutOfBoundsError(NonceOutOfBoundsError::new(revision_nonce)) + .into(), + )); + } + + let voter_identity_id = self.voter_identity_id(); + + let (existing_nonce, fee) = platform.drive.fetch_identity_nonce_with_fees( + voter_identity_id.to_buffer(), + block_info, + true, + tx, + platform_version, + )?; + + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); + + let result = if let Some(existing_nonce) = existing_nonce { + validate_identity_nonce_update(existing_nonce, revision_nonce, voter_identity_id) + } else { + validate_new_identity_nonce(revision_nonce, voter_identity_id) + }; + + Ok(result) + } +} diff --git a/packages/rs-drive-abci/src/query/prefunded_specialized_balances/balance/v0/mod.rs b/packages/rs-drive-abci/src/query/prefunded_specialized_balances/balance/v0/mod.rs index fed648c116a..410a9021959 100644 --- a/packages/rs-drive-abci/src/query/prefunded_specialized_balances/balance/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/prefunded_specialized_balances/balance/v0/mod.rs @@ -50,7 +50,7 @@ impl Platform { let Some(balance) = maybe_balance else { return Ok(ValidationResult::new_with_error(QueryError::NotFound( - "No Identity found".to_string(), + "No Specialized balance found".to_string(), ))); }; diff --git a/packages/rs-drive-abci/src/rpc/core.rs b/packages/rs-drive-abci/src/rpc/core.rs index a16f0341dc6..91ded6f6fe3 100644 --- a/packages/rs-drive-abci/src/rpc/core.rs +++ b/packages/rs-drive-abci/src/rpc/core.rs @@ -152,11 +152,6 @@ pub const CORE_RPC_INVALID_ADDRESS_OR_KEY: i32 = -5; /// Invalid, missing or duplicate parameter pub const CORE_RPC_INVALID_PARAMETER: i32 = -8; -/// Asset Unlock consensus error "bad-assetunlock-not-active-quorum" -pub const CORE_RPC_ERROR_ASSET_UNLOCK_NO_ACTIVE_QUORUM: &str = "bad-assetunlock-not-active-quorum"; -/// Asset Unlock consensus error "bad-assetunlock-not-active-quorum" -pub const CORE_RPC_ERROR_ASSET_UNLOCK_EXPIRED: &str = "bad-assetunlock-too-late"; - macro_rules! retry { ($action:expr) => {{ /// Maximum number of retry attempts diff --git a/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs index 554394956be..6cc875c18fc 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs @@ -783,7 +783,7 @@ mod tests { chain_lock: ChainLockConfig::default_100_67(), instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { - verify_sum_trees: true, + verify_sum_trees: false, //faster without this epoch_time_length_s: 1576800, ..Default::default() }, @@ -1369,7 +1369,7 @@ mod tests { chain_lock: ChainLockConfig::default_100_67(), instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { - verify_sum_trees: true, + verify_sum_trees: false, epoch_time_length_s: 1576800, ..Default::default() }, 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 83834520c0c..3547f94c805 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::execution::{continue_chain_for_strategy, run_chain_for_strategy}; - use crate::strategy::{ChainExecutionOutcome, ChainExecutionParameters, NetworkStrategy, StrategyRandomness}; + use crate::strategy::{ChainExecutionOutcome, ChainExecutionParameters, NetworkStrategy, StrategyRandomness, UpgradingInfo}; use dpp::data_contract::accessors::v0::DataContractV0Getters; use dpp::data_contract::document_type::random_document::{ DocumentFieldFillSize, DocumentFieldFillType, @@ -9,7 +9,7 @@ mod tests { use dpp::identity::accessors::IdentityGettersV0; use dpp::identity::Identity; use dpp::platform_value::Value; - use drive_abci::config::{ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig}; + 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; @@ -23,6 +23,7 @@ mod tests { use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::{get_contested_resource_vote_state_response_v0, GetContestedResourceVoteStateResponseV0}; use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::get_contested_resource_vote_state_response_v0::FinishedVoteInfo; use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::get_contested_resource_vote_state_response_v0::finished_vote_info::FinishedVoteOutcome; + use dpp::block::epoch::Epoch; use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0Getters; use dpp::dash_to_duffs; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; @@ -1322,7 +1323,7 @@ mod tests { } #[test] - fn run_chain_with_voting_on_conflicting_index_distribution_after_won_by_identity() { + fn run_chain_with_voting_after_won_by_identity_no_specialized_funds_distribution() { // In this test we try to insert two state transitions with the same unique index // We use the DPNS contract, and we insert two documents both with the same "name" // This is a common scenario we should see quite often @@ -1341,9 +1342,10 @@ mod tests { }; let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) + .with_initial_protocol_version(7) .build_with_mock_rpc(); - let platform_version = PlatformVersion::latest(); + let platform_version = PlatformVersion::get(7).unwrap(); let mut rng = StdRng::seed_from_u64(567); @@ -1708,5 +1710,1161 @@ mod tests { finished_at_epoch: 1 }) ); + + // not let's see how much is in processing pools + + let processing_fees = platform + .drive + .get_epoch_processing_credits_for_distribution( + &Epoch::new(1).unwrap(), + None, + platform_version, + ) + .expect("expected to get processing fees made in epoch"); + + // A vote costs 10_000_000 + // Hence we did 5 votes in this epoch + assert_eq!(processing_fees, 50_000_000); + } + + #[test] + fn run_chain_with_voting_after_won_by_identity_with_specialized_funds_distribution() { + // In this test we try to insert two state transitions with the same unique index + // We use the DPNS contract, and we insert two documents both with the same "name" + // This is a common scenario we should see quite often + let config = PlatformConfig { + testing_configs: PlatformTestConfig::default_minimal_verifications(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + //we disable document triggers because we are using dpns and dpns needs a preorder + use_document_triggers: false, + + ..Default::default() + }, + block_spacing_ms: 3000, + ..Default::default() + }; + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let platform_version = PlatformVersion::latest(); + + let mut rng = StdRng::seed_from_u64(567); + + let mut simple_signer = SimpleSigner::default(); + + let (identity1, keys1) = + Identity::random_identity_with_main_keys_with_private_key::>( + 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(); + + simple_signer.add_keys(keys2); + + let start_identities: Vec<(Identity, Option)> = + create_state_transitions_for_identities( + vec![identity1, 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 dpns_contract = platform + .drive + .cache + .system_data_contracts + .load_dpns() + .as_ref() + .clone(); + + let document_type = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type") + .to_owned_document_type(); + + let identity1_id = start_identities.first().unwrap().0.id(); + let identity2_id = start_identities.last().unwrap().0.id(); + let document_op_1 = DocumentOp { + contract: dpns_contract.clone(), + action: DocumentAction::DocumentActionInsertSpecific( + BTreeMap::from([ + ("label".into(), "quantum".into()), + ("normalizedLabel".into(), "quantum".into()), + ("normalizedParentDomainName".into(), "dash".into()), + ( + "records".into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), + ), + ]), + Some(start_identities.first().unwrap().0.id()), + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + ), + document_type: document_type.clone(), + }; + + let document_op_2 = DocumentOp { + contract: dpns_contract.clone(), + action: DocumentAction::DocumentActionInsertSpecific( + BTreeMap::from([ + ("label".into(), "quantum".into()), + ("normalizedLabel".into(), "quantum".into()), + ("normalizedParentDomainName".into(), "dash".into()), + ( + "records".into(), + BTreeMap::from([( + "identity", + Value::from(start_identities.last().unwrap().0.id()), + )]) + .into(), + ), + ]), + Some(start_identities.last().unwrap().0.id()), + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + ), + document_type: document_type.clone(), + }; + + let strategy = NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![ + Operation { + op_type: OperationType::Document(document_op_1), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + Operation { + op_type: OperationType::Document(document_op_2), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ], + start_identities: StartIdentities { + hard_coded: start_identities, + ..Default::default() + }, + identity_inserts: Default::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 mut voting_signer = Some(SimpleSigner::default()); + + // On the first block we only have identities and contracts + let ChainExecutionOutcome { + abci_app, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions, + end_time_ms, + identity_nonce_counter, + identity_contract_nonce_counter, + state_transition_results_per_block, + .. + } = run_chain_for_strategy( + &mut platform, + 2, + strategy.clone(), + config.clone(), + 15, + &mut voting_signer, + ); + + let platform = abci_app.platform; + + let platform_state = platform.state.load(); + + let state_transitions_block_2 = state_transition_results_per_block + .get(&2) + .expect("expected to get block 2"); + + let first_document_insert_result = &state_transitions_block_2 + .first() + .as_ref() + .expect("expected a document insert") + .1; + assert_eq!(first_document_insert_result.code, 0); + + let second_document_insert_result = &state_transitions_block_2 + .get(1) + .as_ref() + .expect("expected a document insert") + .1; + + assert_eq!(second_document_insert_result.code, 0); // we expect the second to also be insertable as they are both contested + + let block_start = platform_state + .last_committed_block_info() + .as_ref() + .unwrap() + .basic_info() + .height + + 1; + let day_in_ms = 1000 * 60 * 60 * 24; + let config = PlatformConfig { + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + //we disable document triggers because we are using dpns and dpns needs a preorder + use_document_triggers: false, + + ..Default::default() + }, + block_spacing_ms: day_in_ms, + ..Default::default() + }; + + let outcome = continue_chain_for_strategy( + abci_app, + ChainExecutionParameters { + block_start, + core_height_start: 1, + block_count: 16, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions: Some(current_proposer_versions.clone()), + current_identity_nonce_counter: identity_nonce_counter, + current_identity_contract_nonce_counter: identity_contract_nonce_counter, + current_votes: BTreeMap::default(), + start_time_ms: 1681094380000, + current_time_ms: end_time_ms, + current_identities: Vec::new(), + }, + NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![Operation { + op_type: OperationType::ResourceVote(ResourceVoteOp { + resolved_vote_poll: ContestedDocumentResourceVotePollWithContractInfo { + contract: DataContractOwnedResolvedInfo::OwnedDataContract( + dpns_contract.clone(), + ), + document_type_name: "domain".to_string(), + index_name: "parentNameAndLabel".to_string(), + index_values: vec!["dash".into(), "quantum".into()], + }, + action: VoteAction { + vote_choices_with_weights: vec![ + (ResourceVoteChoice::Abstain, 1), + (ResourceVoteChoice::Lock, 1), + (ResourceVoteChoice::TowardsIdentity(identity1_id), 2), + (ResourceVoteChoice::TowardsIdentity(identity2_id), 10), + ], + }, + }), + frequency: Frequency { + times_per_block_range: 1..3, + chance_per_block: None, + }, + }], + start_identities: StartIdentities::default(), + identity_inserts: Default::default(), + + identity_contract_nonce_gaps: None, + signer: voting_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() + }, + config.clone(), + StrategyRandomness::SeedEntropy(9), + ); + + let platform = outcome.abci_app.platform; + + // Now let's run a query for the vote totals + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config) + .expect("expected to encode the word dash"); + + let quantum_encoded = bincode::encode_to_vec(Value::Text("quantum".to_string()), config) + .expect("expected to encode the word quantum"); + + let index_name = "parentNameAndLabel".to_string(); + + let query_validation_result = platform + .query_contested_resource_vote_state( + GetContestedResourceVoteStateRequest { + version: Some(get_contested_resource_vote_state_request::Version::V0( + GetContestedResourceVoteStateRequestV0 { + contract_id: dpns_contract.id().to_vec(), + document_type_name: document_type.name().clone(), + index_name: index_name.clone(), + index_values: vec![dash_encoded.clone(), quantum_encoded.clone()], + result_type: ResultType::DocumentsAndVoteTally as i32, + allow_include_locked_and_abstaining_vote_tally: true, + start_at_identifier_info: None, + count: None, + prove: false, + }, + )), + }, + &platform_state, + platform_version, + ) + .expect("expected to execute query") + .into_data() + .expect("expected query to be valid"); + + let get_contested_resource_vote_state_response::Version::V0( + GetContestedResourceVoteStateResponseV0 { + metadata: _, + result, + }, + ) = query_validation_result.version.expect("expected a version"); + + let Some( + get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders( + get_contested_resource_vote_state_response_v0::ContestedResourceContenders { + contenders, + abstain_vote_tally, + lock_vote_tally, + finished_vote_info, + }, + ), + ) = result + else { + panic!("expected contenders") + }; + + assert_eq!(contenders.len(), 2); + + let first_contender = contenders.first().unwrap(); + + let second_contender = contenders.last().unwrap(); + + assert_eq!(first_contender.identifier, identity2_id.to_vec()); + + assert_eq!(second_contender.identifier, identity1_id.to_vec()); + + // All vote counts are weighted, so for evonodes, these are in multiples of 4 + + // 19 votes were cast + + assert_eq!(first_contender.vote_count, Some(60)); + + assert_eq!(second_contender.vote_count, Some(4)); + + assert_eq!(lock_vote_tally, Some(4)); + + assert_eq!(abstain_vote_tally, Some(8)); + + assert_eq!( + finished_vote_info, + Some(FinishedVoteInfo { + finished_vote_outcome: FinishedVoteOutcome::TowardsIdentity.into(), + won_by_identity_id: Some(identity2_id.to_vec()), + finished_at_block_height: 17, + finished_at_core_block_height: 1, + finished_at_block_time_ms: 1682303986000, + finished_at_epoch: 1 + }) + ); + + // not let's see how much is in processing pools + + let processing_fees = platform + .drive + .get_epoch_processing_credits_for_distribution( + &Epoch::new(1).unwrap(), + None, + platform_version, + ) + .expect("expected to get processing fees made in epoch"); + + // A vote costs 10_000_000 + // We did 5 votes in this epoch, + // We had 39_810_000_000 left over, which is only the cost of 19 votes + // So we basically have 39_810_000_000 + 50_000_000 + assert_eq!(processing_fees, 39_860_000_000); + } + + #[test] + fn run_chain_with_voting_after_won_by_identity_no_specialized_funds_distribution_until_version_8( + ) { + // In this test the goal is to verify that when we hit version 8 that the specialized balances + // that hadn't been properly distributed are distributed. + let config = PlatformConfig { + validator_set: ValidatorSetConfig { + quorum_size: 10, + ..Default::default() + }, + testing_configs: PlatformTestConfig::default_minimal_verifications(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + //we disable document triggers because we are using dpns and dpns needs a preorder + use_document_triggers: false, + + ..Default::default() + }, + block_spacing_ms: 3000, + ..Default::default() + }; + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .with_initial_protocol_version(7) + .build_with_mock_rpc(); + + let platform_version = PlatformVersion::get(7).unwrap(); + + let mut rng = StdRng::seed_from_u64(567); + + let mut simple_signer = SimpleSigner::default(); + + let (identity1, keys1) = + Identity::random_identity_with_main_keys_with_private_key::>( + 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(); + + simple_signer.add_keys(keys2); + + let start_identities: Vec<(Identity, Option)> = + create_state_transitions_for_identities( + vec![identity1, 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 dpns_contract = platform + .drive + .cache + .system_data_contracts + .load_dpns() + .as_ref() + .clone(); + + let document_type = dpns_contract + .document_type_for_name("domain") + .expect("expected a profile document type") + .to_owned_document_type(); + + let identity1_id = start_identities.first().unwrap().0.id(); + let identity2_id = start_identities.last().unwrap().0.id(); + let document_op_1 = DocumentOp { + contract: dpns_contract.clone(), + action: DocumentAction::DocumentActionInsertSpecific( + BTreeMap::from([ + ("label".into(), "quantum".into()), + ("normalizedLabel".into(), "quantum".into()), + ("normalizedParentDomainName".into(), "dash".into()), + ( + "records".into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), + ), + ]), + Some(identity1_id), + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + ), + document_type: document_type.clone(), + }; + + let document_op_2 = DocumentOp { + contract: dpns_contract.clone(), + action: DocumentAction::DocumentActionInsertSpecific( + BTreeMap::from([ + ("label".into(), "quantum".into()), + ("normalizedLabel".into(), "quantum".into()), + ("normalizedParentDomainName".into(), "dash".into()), + ( + "records".into(), + BTreeMap::from([( + "identity", + Value::from(start_identities.last().unwrap().0.id()), + )]) + .into(), + ), + ]), + Some(identity2_id), + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + ), + document_type: document_type.clone(), + }; + + let strategy = NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![ + Operation { + op_type: OperationType::Document(document_op_1), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + Operation { + op_type: OperationType::Document(document_op_2), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ], + start_identities: StartIdentities { + hard_coded: start_identities, + ..Default::default() + }, + identity_inserts: Default::default(), + + identity_contract_nonce_gaps: None, + signer: Some(simple_signer.clone()), + }, + total_hpmns: 20, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: Some(UpgradingInfo { + current_protocol_version: 7, + proposed_protocol_versions_with_weight: vec![(7, 1)], + upgrade_three_quarters_life: 0.2, + }), + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: true, + ..Default::default() + }; + + let mut voting_signer = Some(SimpleSigner::default()); + + // On the first block we only have identities and contracts + let ChainExecutionOutcome { + abci_app, + identities, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions, + end_time_ms, + identity_nonce_counter, + identity_contract_nonce_counter, + state_transition_results_per_block, + .. + } = run_chain_for_strategy( + &mut platform, + 2, + strategy.clone(), + config.clone(), + 15, + &mut voting_signer, + ); + + let platform = abci_app.platform; + + let platform_state = platform.state.load(); + + let state_transitions_block_2 = state_transition_results_per_block + .get(&2) + .expect("expected to get block 2"); + + let first_document_insert_result = &state_transitions_block_2 + .first() + .as_ref() + .expect("expected a document insert") + .1; + assert_eq!(first_document_insert_result.code, 0); + + let second_document_insert_result = &state_transitions_block_2 + .get(1) + .as_ref() + .expect("expected a document insert") + .1; + + assert_eq!(second_document_insert_result.code, 0); // we expect the second to also be insertable as they are both contested + + let block_start = platform_state + .last_committed_block_info() + .as_ref() + .unwrap() + .basic_info() + .height + + 1; + let day_in_ms = 1000 * 60 * 60 * 24; + let config = PlatformConfig { + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + //we disable document triggers because we are using dpns and dpns needs a preorder + use_document_triggers: false, + + ..Default::default() + }, + block_spacing_ms: day_in_ms, + ..Default::default() + }; + + // On the first block we only have identities and contracts + let ChainExecutionOutcome { + abci_app, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + end_time_ms, + identity_nonce_counter, + identity_contract_nonce_counter, + .. + } = continue_chain_for_strategy( + abci_app, + ChainExecutionParameters { + block_start, + core_height_start: 1, + block_count: 16, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions: Some(current_proposer_versions.clone()), + current_identity_nonce_counter: identity_nonce_counter, + current_identity_contract_nonce_counter: identity_contract_nonce_counter, + current_votes: BTreeMap::default(), + start_time_ms: 1681094380000, + current_time_ms: end_time_ms, + current_identities: Vec::new(), + }, + NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![Operation { + op_type: OperationType::ResourceVote(ResourceVoteOp { + resolved_vote_poll: ContestedDocumentResourceVotePollWithContractInfo { + contract: DataContractOwnedResolvedInfo::OwnedDataContract( + dpns_contract.clone(), + ), + document_type_name: "domain".to_string(), + index_name: "parentNameAndLabel".to_string(), + index_values: vec!["dash".into(), "quantum".into()], + }, + action: VoteAction { + vote_choices_with_weights: vec![ + (ResourceVoteChoice::Abstain, 1), + (ResourceVoteChoice::Lock, 1), + (ResourceVoteChoice::TowardsIdentity(identity1_id), 2), + (ResourceVoteChoice::TowardsIdentity(identity2_id), 10), + ], + }, + }), + frequency: Frequency { + times_per_block_range: 1..3, + chance_per_block: None, + }, + }], + start_identities: StartIdentities::default(), + identity_inserts: Default::default(), + + identity_contract_nonce_gaps: None, + signer: voting_signer, + }, + total_hpmns: 20, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: Some(UpgradingInfo { + current_protocol_version: 7, + proposed_protocol_versions_with_weight: vec![(7, 1)], + upgrade_three_quarters_life: 0.2, + }), + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: true, + ..Default::default() + }, + config.clone(), + StrategyRandomness::SeedEntropy(9), + ); + + let platform = abci_app.platform; + + // Now let's run a query for the vote totals + + let bincode_config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), bincode_config) + .expect("expected to encode the word dash"); + + let quantum_encoded = + bincode::encode_to_vec(Value::Text("quantum".to_string()), bincode_config) + .expect("expected to encode the word quantum"); + + let index_name = "parentNameAndLabel".to_string(); + + let query_validation_result = platform + .query_contested_resource_vote_state( + GetContestedResourceVoteStateRequest { + version: Some(get_contested_resource_vote_state_request::Version::V0( + GetContestedResourceVoteStateRequestV0 { + contract_id: dpns_contract.id().to_vec(), + document_type_name: document_type.name().clone(), + index_name: index_name.clone(), + index_values: vec![dash_encoded.clone(), quantum_encoded.clone()], + result_type: ResultType::DocumentsAndVoteTally as i32, + allow_include_locked_and_abstaining_vote_tally: true, + start_at_identifier_info: None, + count: None, + prove: false, + }, + )), + }, + &platform_state, + platform_version, + ) + .expect("expected to execute query") + .into_data() + .expect("expected query to be valid"); + + let get_contested_resource_vote_state_response::Version::V0( + GetContestedResourceVoteStateResponseV0 { + metadata: _, + result, + }, + ) = query_validation_result.version.expect("expected a version"); + + let Some( + get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders( + get_contested_resource_vote_state_response_v0::ContestedResourceContenders { + contenders, + abstain_vote_tally, + lock_vote_tally, + finished_vote_info, + }, + ), + ) = result + else { + panic!("expected contenders") + }; + + assert_eq!(contenders.len(), 2); + + let first_contender = contenders.first().unwrap(); + + let second_contender = contenders.last().unwrap(); + + assert_eq!(first_contender.identifier, identity2_id.to_vec()); + + assert_eq!(second_contender.identifier, identity1_id.to_vec()); + + // All vote counts are weighted, so for evonodes, these are in multiples of 4 + + assert_eq!( + ( + first_contender.vote_count, + second_contender.vote_count, + lock_vote_tally, + abstain_vote_tally + ), + (Some(64), Some(8), Some(0), Some(0)) + ); + + assert_eq!( + finished_vote_info, + Some(FinishedVoteInfo { + finished_vote_outcome: FinishedVoteOutcome::TowardsIdentity.into(), + won_by_identity_id: Some(identity2_id.to_vec()), + finished_at_block_height: 17, + finished_at_core_block_height: 1, + finished_at_block_time_ms: 1682303986000, + finished_at_epoch: 1 + }) + ); + + // not let's see how much is in processing pools + + let processing_fees = platform + .drive + .get_epoch_processing_credits_for_distribution( + &Epoch::new(1).unwrap(), + None, + platform_version, + ) + .expect("expected to get processing fees made in epoch"); + + // A vote costs 10_000_000 + // Hence we did 4 votes in this epoch + assert_eq!(processing_fees, 40_000_000); + + // Now let's upgrade to version 8 + + let platform = abci_app.platform; + + let platform_state = platform.state.load(); + + let block_start = platform_state + .last_committed_block_info() + .as_ref() + .unwrap() + .basic_info() + .height + + 1; + + let ten_hours_in_ms = 1000 * 60 * 60 * 10; + let config = PlatformConfig { + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + //we disable document triggers because we are using dpns and dpns needs a preorder + use_document_triggers: false, + + ..Default::default() + }, + block_spacing_ms: ten_hours_in_ms, + ..Default::default() + }; + + // We go 45 blocks later + let ChainExecutionOutcome { + abci_app, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + end_time_ms, + identity_nonce_counter, + identity_contract_nonce_counter, + .. + } = continue_chain_for_strategy( + abci_app, + ChainExecutionParameters { + block_start, + core_height_start: 1, + block_count: 45, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions: None, + current_identity_nonce_counter: identity_nonce_counter, + current_identity_contract_nonce_counter: identity_contract_nonce_counter, + current_votes: BTreeMap::default(), + start_time_ms: 1681094380000, + current_time_ms: end_time_ms, + current_identities: Vec::new(), + }, + NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![], + start_identities: StartIdentities::default(), + identity_inserts: Default::default(), + + identity_contract_nonce_gaps: None, + signer: None, + }, + total_hpmns: 20, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: Some(UpgradingInfo { + current_protocol_version: 8, + proposed_protocol_versions_with_weight: vec![(8, 1)], + upgrade_three_quarters_life: 0.1, + }), + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: false, + ..Default::default() + }, + config.clone(), + StrategyRandomness::SeedEntropy(9203), + ); + + let platform = abci_app.platform; + + let platform_state = platform.state.load(); + + let mut block_start = platform_state + .last_committed_block_info() + .as_ref() + .unwrap() + .basic_info() + .height + + 1; + + // We need to create a few more contests + + let document_op_1 = DocumentOp { + contract: dpns_contract.clone(), + action: DocumentAction::DocumentActionInsertSpecific( + BTreeMap::from([ + ("label".into(), "sam".into()), + ("normalizedLabel".into(), "sam".into()), + ("normalizedParentDomainName".into(), "dash".into()), + ("parentDomainName".into(), "dash".into()), + ( + "records".into(), + BTreeMap::from([("identity", Value::from(identity1_id))]).into(), + ), + ]), + Some(identity1_id), + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + ), + document_type: document_type.clone(), + }; + + let document_op_2 = DocumentOp { + contract: dpns_contract.clone(), + action: DocumentAction::DocumentActionInsertSpecific( + BTreeMap::from([ + ("label".into(), "sam".into()), + ("normalizedLabel".into(), "sam".into()), + ("normalizedParentDomainName".into(), "dash".into()), + ("parentDomainName".into(), "dash".into()), + ( + "records".into(), + BTreeMap::from([("identity", Value::from(identity2_id))]).into(), + ), + ]), + Some(identity2_id), + DocumentFieldFillType::FillIfNotRequired, + DocumentFieldFillSize::AnyDocumentFillSize, + ), + document_type: document_type.clone(), + }; + + let ChainExecutionOutcome { + abci_app, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + end_time_ms, + identity_nonce_counter, + identity_contract_nonce_counter, + .. + } = continue_chain_for_strategy( + abci_app, + ChainExecutionParameters { + block_start, + core_height_start: 1, + block_count: 1, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions: None, + current_identity_nonce_counter: identity_nonce_counter, + current_identity_contract_nonce_counter: identity_contract_nonce_counter, + current_votes: BTreeMap::default(), + start_time_ms: 1681094380000, + current_time_ms: end_time_ms, + current_identities: identities, + }, + NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![ + Operation { + op_type: OperationType::Document(document_op_1), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + Operation { + op_type: OperationType::Document(document_op_2), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ], + start_identities: StartIdentities::default(), + identity_inserts: Default::default(), + + identity_contract_nonce_gaps: None, + signer: Some(simple_signer), + }, + total_hpmns: 20, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: Some(UpgradingInfo { + current_protocol_version: 8, + proposed_protocol_versions_with_weight: vec![(8, 1)], + upgrade_three_quarters_life: 0.1, + }), + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: false, + ..Default::default() + }, + config.clone(), + StrategyRandomness::SeedEntropy(9203), + ); + + block_start += 1; + + // We go 14 blocks later till version 8 is active + let outcome = continue_chain_for_strategy( + abci_app, + ChainExecutionParameters { + block_start, + core_height_start: 1, + block_count: 14, + proposers, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, + current_proposer_versions: None, + current_identity_nonce_counter: identity_nonce_counter, + current_identity_contract_nonce_counter: identity_contract_nonce_counter, + current_votes: BTreeMap::default(), + start_time_ms: 1681094380000, + current_time_ms: end_time_ms, + current_identities: Vec::new(), + }, + NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![], + start_identities: StartIdentities::default(), + identity_inserts: Default::default(), + + identity_contract_nonce_gaps: None, + signer: None, + }, + total_hpmns: 20, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: Some(UpgradingInfo { + current_protocol_version: 8, + proposed_protocol_versions_with_weight: vec![(8, 1)], + upgrade_three_quarters_life: 0.1, + }), + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + verify_state_transition_results: false, + ..Default::default() + }, + config.clone(), + StrategyRandomness::SeedEntropy(9203), + ); + + let platform = outcome.abci_app.platform; + platform + .drive + .fetch_versions_with_counter(None, &platform_version.drive) + .expect("expected to get versions"); + + let state = platform.state.load(); + assert_eq!( + state + .last_committed_block_info() + .as_ref() + .unwrap() + .basic_info() + .epoch + .index, + 4 + ); + assert_eq!(state.current_protocol_version_in_consensus(), 8); + + let processing_fees = platform + .drive + .get_epoch_processing_credits_for_distribution( + &Epoch::new(4).unwrap(), + None, + platform_version, + ) + .expect("expected to get processing fees made in epoch"); + + // A vote costs 10_000_000 + // There were 23 votes total so that means that there would have been 39_780_000_000 left over + // We see that there is 39_780_000_000 to distribute + assert_eq!(processing_fees, 39_780_000_000); } } diff --git a/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-documents-mutable.json b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-documents-mutable.json new file mode 100644 index 00000000000..f4833eed719 --- /dev/null +++ b/packages/rs-drive-abci/tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-documents-mutable.json @@ -0,0 +1,134 @@ +{ + "$format_version": "0", + "id": "86LHvdC1Tqx5P97LQUSibGFqf2vnKFpB6VkqQ7oso86e", + "ownerId": "2QjL594djCH2NyDsn45vd6yQjEDHupMKo7CEGVTHtQxU", + "version": 1, + "documentSchemas": { + "card": { + "type": "object", + "documentsMutable": true, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 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-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index e19a9ced1b5..00082eed054 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "drive-proof-verifier" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 7af925f26c0..6bc09663429 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "drive" description = "Dash drive built on top of GroveDB" -version = "1.7.0" +version = "1.8.0" authors = [ "Samuel Westrich ", "Ivan Shumkov ", @@ -49,15 +49,15 @@ bs58 = { version = "0.5.0", optional = true } base64 = { version = "0.22.1", optional = true } tempfile = { version = "3", optional = true } enum-map = { version = "2.0.3", optional = true } -intmap = { version = "2.0.0", features = ["serde"], 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.1.0", optional = true, default-features = false } -grovedb-costs = { version = "2.1.0", optional = true } -grovedb-path = { version = "2.1.0" } -grovedb-storage = { version = "2.1.0", optional = true } -grovedb-version = { version = "2.1.0" } -grovedb-epoch-based-storage-flags = { version = "2.1.0" } +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" } [dev-dependencies] criterion = "0.5" @@ -104,7 +104,7 @@ server = [ "dpp/system_contracts", "dpp/state-transitions", "fee-distribution", - "grovedb/full", + "grovedb/minimal", "grovedb/estimated_costs", "grovedb-storage", "grovedb-costs", diff --git a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/add_epoch_processing_credits_for_distribution_operation/mod.rs b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/add_epoch_processing_credits_for_distribution_operation/mod.rs new file mode 100644 index 00000000000..51d7d325873 --- /dev/null +++ b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/add_epoch_processing_credits_for_distribution_operation/mod.rs @@ -0,0 +1,56 @@ +mod v0; + +use grovedb::TransactionArg; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; + +use dpp::block::epoch::Epoch; +use dpp::fee::Credits; + +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::PlatformVersion; + +impl Drive { + /// Adds to the amount of processing fees to be distributed for the Epoch. + /// + /// # Arguments + /// + /// * `epoch_tree` - A reference to the Epoch. + /// * `amount` - The amount to add. + /// * `transaction` - A TransactionArg instance. + /// * `platform_version` - A PlatformVersion instance representing the version of the drive. + /// + /// # Returns + /// + /// A Result containing either the processing fee for the epoch, if found, + /// or an Error if something goes wrong. + pub fn add_epoch_processing_credits_for_distribution_operation( + &self, + epoch: &Epoch, + amount: Credits, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .credit_pools + .epochs + .add_epoch_processing_credits_for_distribution_operation + { + 0 => self.add_epoch_processing_credits_for_distribution_operation_v0( + epoch, + amount, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "add_epoch_processing_credits_for_distribution_operation".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/add_epoch_processing_credits_for_distribution_operation/v0/mod.rs b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/add_epoch_processing_credits_for_distribution_operation/v0/mod.rs new file mode 100644 index 00000000000..f163236b475 --- /dev/null +++ b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/add_epoch_processing_credits_for_distribution_operation/v0/mod.rs @@ -0,0 +1,60 @@ +use grovedb::{Element, TransactionArg}; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; + +use crate::drive::credit_pools::epochs::epoch_key_constants; +use crate::drive::credit_pools::epochs::paths::EpochProposers; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use dpp::block::epoch::Epoch; +use dpp::fee::Credits; +use dpp::ProtocolError; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Gets the amount of processing fees to be distributed for the Epoch and adds to it. + pub(super) fn add_epoch_processing_credits_for_distribution_operation_v0( + &self, + epoch: &Epoch, + amount: Credits, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let epoch_tree_path = epoch.get_path(); + let element = self.grove_get_raw_optional( + (&epoch_tree_path).into(), + epoch_key_constants::KEY_POOL_PROCESSING_FEES.as_slice(), + DirectQueryType::StatefulDirectQuery, + transaction, + &mut vec![], + &platform_version.drive, + )?; + + let existing_value = match element { + None => 0, + Some(Element::SumItem(existing_value, _)) => existing_value, + _ => { + return Err(Error::Drive(DriveError::UnexpectedElementType( + "epochs processing fee must be an item", + ))) + } + }; + + if amount > i64::MAX as u64 { + return Err(Error::Protocol(ProtocolError::Overflow( + "adding over i64::Max to processing fee pool", + ))); + } + + let updated_value = existing_value + .checked_add(amount as i64) + .ok_or(ProtocolError::Overflow("overflow when adding to sum item"))?; + Ok(LowLevelDriveOperation::insert_for_known_path_key_element( + epoch_tree_path.iter().map(|a| a.to_vec()).collect(), + epoch_key_constants::KEY_POOL_PROCESSING_FEES.to_vec(), + Element::new_sum_item(updated_value), + )) + } +} diff --git a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/mod.rs b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/mod.rs index 8e790b846bf..db40e29f00b 100644 --- a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/mod.rs +++ b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/mod.rs @@ -26,7 +26,7 @@ impl Drive { /// or an Error if something goes wrong. pub fn get_epoch_processing_credits_for_distribution( &self, - epoch_tree: &Epoch, + epoch: &Epoch, transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result { @@ -38,7 +38,7 @@ impl Drive { .get_epoch_processing_credits_for_distribution { 0 => self.get_epoch_processing_credits_for_distribution_v0( - epoch_tree, + epoch, transaction, platform_version, ), diff --git a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/v0/mod.rs b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/v0/mod.rs index 05782b23b2b..ae0265d3930 100644 --- a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/v0/mod.rs +++ b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/get_epoch_processing_credits_for_distribution/v0/mod.rs @@ -15,14 +15,14 @@ impl Drive { /// Gets the amount of processing fees to be distributed for the Epoch. pub(super) fn get_epoch_processing_credits_for_distribution_v0( &self, - epoch_tree: &Epoch, + epoch: &Epoch, transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result { let element = self .grove .get( - &epoch_tree.get_path(), + &epoch.get_path(), epoch_key_constants::KEY_POOL_PROCESSING_FEES.as_slice(), transaction, &platform_version.drive.grove_version, diff --git a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/mod.rs b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/mod.rs index f0a061ce024..2096f129060 100644 --- a/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/mod.rs +++ b/packages/rs-drive/src/drive/credit_pools/epochs/credit_distribution_pools/mod.rs @@ -3,6 +3,7 @@ //! This module implements functions in Drive to distribute fees for a given Epoch. //! +mod add_epoch_processing_credits_for_distribution_operation; mod get_epoch_fee_multiplier; mod get_epoch_processing_credits_for_distribution; mod get_epoch_storage_credits_for_distribution; 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 7d70f79819e..cf2b79c56d6 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 @@ -77,17 +77,17 @@ impl Drive { )), ))?; - Ok((s as u64, layer_info.clone())) + Ok((s, layer_info.clone())) }) - .collect::, Error>>()?; + .collect::, Error>>()?; // We need to update the current layer to only have 1 element that we want to delete let mut last_layer_information = layer_map - .remove((key_info_path.len() - 1) as u64) + .remove((key_info_path.len() - 1) as u16) .ok_or(Error::Fee(FeeError::CorruptedEstimatedLayerInfoMissing( "last layer info missing".to_owned(), )))?; last_layer_information.estimated_layer_sizes = element_estimated_sizes; - layer_map.insert((key_info_path.len() - 1) as u64, last_layer_information); + layer_map.insert((key_info_path.len() - 1) as u16, last_layer_information); Ok(BatchDeleteUpTreeApplyType::StatelessBatchDelete { estimated_layer_info: layer_map, }) diff --git a/packages/rs-drive/src/drive/document/insert/mod.rs b/packages/rs-drive/src/drive/document/insert/mod.rs index f0eb33b8a78..d439a05e99d 100644 --- a/packages/rs-drive/src/drive/document/insert/mod.rs +++ b/packages/rs-drive/src/drive/document/insert/mod.rs @@ -315,78 +315,86 @@ mod tests { } #[test] - fn test_add_dashpay_profile_with_fee() { - let drive = setup_drive_with_initial_state_structure(None); + fn test_add_dashpay_profile_with_fee_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 1305 + * Epoch::new(0).unwrap().cost_for_known_cost_item( + &EPOCH_CHANGE_FEE_VERSION_TEST, + StorageDiskUsageCreditPerByte, + ), + processing_fee: 900400, + ..Default::default() + }; + + do_test_add_dashpay_profile_with_fee(true, platform_version, expected_fee_result); + } - let db_transaction = drive.grove.start_transaction(); + #[test] + fn test_add_dashpay_profile_with_fee_first_version_estimated() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 1305 + * Epoch::new(0).unwrap().cost_for_known_cost_item( + &EPOCH_CHANGE_FEE_VERSION_TEST, + StorageDiskUsageCreditPerByte, + ), + processing_fee: 73253660, + ..Default::default() + }; + + do_test_add_dashpay_profile_with_fee(false, platform_version, expected_fee_result); + } + #[test] + fn test_add_dashpay_profile_with_fee_latest_version_apply() { let platform_version = PlatformVersion::latest(); - - let contract = setup_contract( - &drive, - "tests/supporting_files/contract/dashpay/dashpay-contract.json", - None, - Some(&db_transaction), - ); - - let document_type = contract - .document_type_for_name("profile") - .expect("expected to get document type"); - - let random_owner_id = rand::thread_rng().gen::<[u8; 32]>(); - - let dashpay_profile_document = json_document_to_document( - "tests/supporting_files/contract/dashpay/profile0.json", - Some(random_owner_id.into()), - document_type, - platform_version, - ) - .expect("expected to get cbor document"); - - let fee_result = drive - .add_document_for_contract( - DocumentAndContractInfo { - owned_document_info: OwnedDocumentInfo { - document_info: DocumentRefInfo(( - &dashpay_profile_document, - StorageFlags::optional_default_as_cow(), - )), - owner_id: Some(random_owner_id), - }, - contract: &contract, - document_type, - }, - false, - BlockInfo::default(), - true, - Some(&db_transaction), - platform_version, - None, - ) - .expect("expected to insert a document successfully"); - - assert_eq!( - fee_result, - FeeResult { - storage_fee: 1305 - * Epoch::new(0).unwrap().cost_for_known_cost_item( - &EPOCH_CHANGE_FEE_VERSION_TEST, - StorageDiskUsageCreditPerByte, - ), - processing_fee: 900400, - ..Default::default() - } - ); + let expected_fee_result = FeeResult { + storage_fee: 1305 + * Epoch::new(0).unwrap().cost_for_known_cost_item( + &EPOCH_CHANGE_FEE_VERSION_TEST, + StorageDiskUsageCreditPerByte, + ), + processing_fee: 900400, + ..Default::default() + }; + + do_test_add_dashpay_profile_with_fee(true, platform_version, expected_fee_result); } #[test] - fn test_add_dashpay_profile_average_case_cost_fee() { + fn test_add_dashpay_profile_with_fee_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 1305 + * Epoch::new(0).unwrap().cost_for_known_cost_item( + &EPOCH_CHANGE_FEE_VERSION_TEST, + StorageDiskUsageCreditPerByte, + ), + processing_fee: 73253660, + ..Default::default() + }; + + do_test_add_dashpay_profile_with_fee(false, platform_version, expected_fee_result); + } + + /// This helper sets up the environment, adds a dashpay profile document, + /// and either applies or just estimates the cost. + /// + /// `apply`: if true, we commit the transaction (applying the changes). + /// if false, we do not commit, so changes are only estimated. + /// `platform_version`: which PlatformVersion to use. + /// `expected_fee_result`: the FeeResult we expect in the test assertion. + fn do_test_add_dashpay_profile_with_fee( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { let drive = setup_drive_with_initial_state_structure(None); let db_transaction = drive.grove.start_transaction(); - let platform_version = PlatformVersion::latest(); - + // Setup contract let contract = setup_contract( &drive, "tests/supporting_files/contract/dashpay/dashpay-contract.json", @@ -398,8 +406,9 @@ mod tests { .document_type_for_name("profile") .expect("expected to get document type"); - let random_owner_id = rand::thread_rng().gen::<[u8; 32]>(); + let random_owner_id = random::<[u8; 32]>(); + // Build dashpay profile doc let dashpay_profile_document = json_document_to_document( "tests/supporting_files/contract/dashpay/profile0.json", Some(random_owner_id.into()), @@ -408,12 +417,8 @@ mod tests { ) .expect("expected to get cbor document"); - let FeeResult { - storage_fee, - processing_fee, - fee_refunds: _, - removed_bytes_from_system: _, - } = drive + // Perform the add operation, with either an apply or a dry run + let fee_result = drive .add_document_for_contract( DocumentAndContractInfo { owned_document_info: OwnedDocumentInfo { @@ -426,22 +431,16 @@ mod tests { contract: &contract, document_type, }, - false, + false, // override BlockInfo::default(), - false, + apply, Some(&db_transaction), platform_version, None, ) .expect("expected to insert a document successfully"); - let added_bytes = storage_fee - / Epoch::new(0).unwrap().cost_for_known_cost_item( - &EPOCH_CHANGE_FEE_VERSION_TEST, - StorageDiskUsageCreditPerByte, - ); - assert_eq!(1305, added_bytes); - assert_eq!(73253660, processing_fee); + assert_eq!(fee_result, expected_fee_result); } #[test] diff --git a/packages/rs-drive/src/drive/identity/balance/update.rs b/packages/rs-drive/src/drive/identity/balance/update.rs index dc7c94e3e76..aed30f9b248 100644 --- a/packages/rs-drive/src/drive/identity/balance/update.rs +++ b/packages/rs-drive/src/drive/identity/balance/update.rs @@ -21,10 +21,61 @@ mod tests { use super::*; #[test] - fn should_add_to_balance() { - let drive = setup_drive_with_initial_state_structure(None); + fn should_add_to_balance_first_version_apply() { + let platform_version = PlatformVersion::first(); + // Use the same fee result if you want, or adjust if needed: + let expected_fee_result = FeeResult { + processing_fee: 174660, + removed_bytes_from_system: 0, + ..Default::default() + }; + do_should_add_to_balance(true, platform_version, expected_fee_result); + } + + #[test] + fn should_add_to_balance_first_version_estimated() { + let platform_version = PlatformVersion::first(); + // Use the same fee result if you want, or adjust if needed: + let expected_fee_result = FeeResult { + processing_fee: 4278840, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_add_to_balance(false, platform_version, expected_fee_result); + } + + #[test] + fn should_add_to_balance_latest_version_apply() { let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + processing_fee: 174660, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_add_to_balance(true, platform_version, expected_fee_result); + } + + #[test] + fn should_add_to_balance_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + processing_fee: 4278840, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_add_to_balance(false, platform_version, expected_fee_result); + } + + fn do_should_add_to_balance( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -33,6 +84,7 @@ mod tests { let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + // Add new identity (always apply here so it actually gets inserted) drive .add_new_identity( identity.clone(), @@ -48,43 +100,41 @@ mod tests { let amount = 300; + // Add to the identity balance, either applying or estimating let fee_result = drive .add_to_identity_balance( identity.id().to_buffer(), amount, &block_info, - true, + apply, 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); + assert_eq!(fee_result, expected_fee_result); + + if apply { + // Commit if we are applying + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + + // Check the updated balance + 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] @@ -110,9 +160,45 @@ mod tests { } #[test] - fn should_deduct_from_debt_if_balance_is_nil() { - let drive = setup_drive_with_initial_state_structure(None); + fn should_deduct_from_debt_if_balance_is_nil_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 385160, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_deduct_from_debt_if_balance_is_nil( + true, + platform_version, + expected_fee_result, + ); + } + + #[test] + fn should_deduct_from_debt_if_balance_is_nil_latest_version_apply() { let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 385160, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_deduct_from_debt_if_balance_is_nil( + true, + platform_version, + expected_fee_result, + ); + } + + fn do_should_deduct_from_debt_if_balance_is_nil( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); let identity = create_test_identity(&drive, [0; 32], Some(1), None, platform_version) .expect("expected an identity"); @@ -147,55 +233,86 @@ mod tests { identity.id().to_buffer(), added_balance, &block_info, - true, + apply, 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() - } - ); + assert_eq!(fee_result, expected_fee_result); + + if apply { + 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 negative balance") + .expect("negative balance should present"); + + assert_eq!(updated_negative_balance, 0); + } + } - 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"); + #[test] + fn should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 260540, + removed_bytes_from_system: 0, + ..Default::default() + }; - assert_eq!( - updated_balance.expect("balance should present"), - added_balance - negative_amount + do_should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower( + true, + platform_version, + expected_fee_result, ); + } - 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"); + #[test] + fn should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower_latest_version_apply() + { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 260540, + removed_bytes_from_system: 0, + ..Default::default() + }; - assert_eq!(updated_negative_balance, 0) + do_should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower( + true, + platform_version, + expected_fee_result, + ); } - #[test] - fn should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower() { + fn do_should_keep_nil_balance_and_reduce_debt_if_added_balance_is_lower( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { 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"); @@ -229,130 +346,117 @@ mod tests { identity.id().to_buffer(), added_balance, &block_info, - true, + apply, 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!(fee_result, expected_fee_result); + + if apply { + 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); + } + } + } - assert_eq!(updated_balance.expect("balance should present"), 0); + mod remove_from_identity_balance { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::fee::fee_result::FeeResult; + use dpp::version::PlatformVersion; - 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"); + #[test] + fn should_remove_from_balance_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + processing_fee: 174660, + removed_bytes_from_system: 0, + ..Default::default() + }; - assert_eq!(updated_negative_balance, negative_amount - added_balance) + do_should_remove_from_balance(true, platform_version, expected_fee_result); } #[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"); + fn should_remove_from_balance_first_version_estimated() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + processing_fee: 2476860, + removed_bytes_from_system: 0, + ..Default::default() + }; - assert_eq!( - fee_result, - FeeResult { - processing_fee: 4278840, - ..Default::default() - } - ); + do_should_remove_from_balance(false, platform_version, expected_fee_result); + } - let app_hash_after = drive - .grove - .root_hash(None, &platform_version.drive.grove_version) - .unwrap() - .expect("should return app hash"); + #[test] + fn should_remove_from_balance_latest_version_apply() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + processing_fee: 174660, + removed_bytes_from_system: 0, + ..Default::default() + }; - assert_eq!(app_hash_after, app_hash_before); + do_should_remove_from_balance(true, platform_version, expected_fee_result); + } - let (balance, _fee_cost) = drive - .fetch_identity_balance_with_costs( - identity.id().to_buffer(), - &block, - true, - None, - platform_version, - ) - .expect("expected to get balance"); + #[test] + fn should_remove_from_balance_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + processing_fee: 2476860, + removed_bytes_from_system: 0, + ..Default::default() + }; - assert!(balance.is_none()); //shouldn't have changed + do_should_remove_from_balance(false, platform_version, expected_fee_result); } - } - 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() { + fn do_should_remove_from_balance( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { 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()); + let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + // Insert the identity with apply=true so it's actually stored drive .add_new_identity( identity.clone(), false, - &block, + &block_info, true, None, platform_version, @@ -367,100 +471,35 @@ mod tests { .remove_from_identity_balance( identity.id().to_buffer(), amount, - &block, - true, + &block_info, + apply, Some(&db_transaction), platform_version, None, ) - .expect("expected to add to identity balance"); + .expect("expected to remove from identity balance"); - assert_eq!( - fee_result, - FeeResult { - processing_fee: 174660, - removed_bytes_from_system: 0, - ..Default::default() - } - ); + assert_eq!(fee_result, expected_fee_result); - 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"); + if apply { + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); - 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"); + 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!(balance.is_none()); //shouldn't have changed + assert_eq!(balance.unwrap(), old_balance - amount); + } } } 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 bd03fbe38b6..3494ceb37ca 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 @@ -121,3 +121,104 @@ impl Drive { } } } + +#[cfg(test)] +mod tests { + use crate::util::test_helpers::setup::setup_drive; + use dpp::identity::Identity; + + use dpp::block::block_info::BlockInfo; + use dpp::fee::fee_result::FeeResult; + use dpp::identity::accessors::IdentityGettersV0; + + use dpp::version::PlatformVersion; + + #[test] + fn test_insert_and_fetch_identity_first_version() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 128871000, + processing_fee: 2330320, + ..Default::default() + }; + + test_insert_and_fetch_identity(true, platform_version, expected_fee_result); + } + + #[test] + fn test_insert_and_fetch_identity_latest_version() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 128871000, + processing_fee: 2330320, + ..Default::default() + }; + + test_insert_and_fetch_identity(true, platform_version, expected_fee_result); + } + + #[test] + fn test_insert_identity_estimated_costs_first_version() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 128871000, + processing_fee: 11764980, + ..Default::default() + }; + + test_insert_and_fetch_identity(false, platform_version, expected_fee_result); + } + + #[test] + fn test_insert_identity_estimated_costs_latest_version() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 128871000, + processing_fee: 11764980, + ..Default::default() + }; + + test_insert_and_fetch_identity(false, platform_version, expected_fee_result); + } + + fn test_insert_and_fetch_identity( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive(None); + + let transaction = drive.grove.start_transaction(); + + drive + .create_initial_state_structure(Some(&transaction), platform_version) + .expect("expected to create root tree successfully"); + + let identity = Identity::random_identity(5, Some(12345), platform_version) + .expect("expected a random identity"); + + let fee_result = drive + .add_new_identity( + identity.clone(), + false, + &BlockInfo::default(), + apply, + Some(&transaction), + platform_version, + ) + .expect("expected to insert identity"); + + if apply { + let fetched_identity = drive + .fetch_full_identity( + identity.id().to_buffer(), + Some(&transaction), + platform_version, + ) + .expect("should fetch an identity") + .expect("should have an identity"); + assert_eq!(identity, fetched_identity); + } + assert_eq!(fee_result, expected_fee_result); + } +} 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 f7562344318..536d680821f 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 @@ -270,80 +270,3 @@ impl Drive { Ok(batch_operations) } } - -#[cfg(test)] -mod tests { - use crate::util::test_helpers::setup::{setup_drive, setup_drive_with_initial_state_structure}; - use dpp::identity::Identity; - - use dpp::block::block_info::BlockInfo; - use dpp::identity::accessors::IdentityGettersV0; - - use dpp::version::PlatformVersion; - - #[test] - fn test_insert_and_fetch_identity_v0() { - let drive = setup_drive(None); - let platform_version = PlatformVersion::first(); - - let transaction = drive.grove.start_transaction(); - - drive - .create_initial_state_structure(Some(&transaction), platform_version) - .expect("expected to create root tree successfully"); - - let identity = Identity::random_identity(5, Some(12345), platform_version) - .expect("expected a random identity"); - - drive - .add_new_identity_v0( - identity.clone(), - false, - &BlockInfo::default(), - true, - Some(&transaction), - platform_version, - ) - .expect("expected to insert identity"); - - let fetched_identity = drive - .fetch_full_identity( - identity.id().to_buffer(), - Some(&transaction), - platform_version, - ) - .expect("should fetch an identity") - .expect("should have an identity"); - - assert_eq!(identity, fetched_identity); - } - - #[test] - fn test_insert_identity_v0() { - let drive = setup_drive_with_initial_state_structure(None); - - let db_transaction = drive.grove.start_transaction(); - - let platform_version = PlatformVersion::latest(); - - let identity = Identity::random_identity(5, Some(12345), platform_version) - .expect("expected a random identity"); - - drive - .add_new_identity_v0( - identity, - false, - &BlockInfo::default(), - true, - Some(&db_transaction), - platform_version, - ) - .expect("expected to insert identity"); - - drive - .grove - .commit_transaction(db_transaction) - .unwrap() - .expect("expected to be able to commit a transaction"); - } -} diff --git a/packages/rs-drive/src/drive/identity/update/mod.rs b/packages/rs-drive/src/drive/identity/update/mod.rs index c846d8d43dd..bae24132457 100644 --- a/packages/rs-drive/src/drive/identity/update/mod.rs +++ b/packages/rs-drive/src/drive/identity/update/mod.rs @@ -14,28 +14,87 @@ mod tests { mod add_new_keys_to_identity { use super::*; + use crate::drive::Drive; + use crate::fees::op::LowLevelDriveOperation; use dpp::block::block_info::BlockInfo; use dpp::block::epoch::Epoch; use dpp::fee::fee_result::FeeResult; use dpp::version::PlatformVersion; + use rand::prelude::StdRng; + use rand::{Rng, SeedableRng}; + // ------------------------------------------------- + // should_add_one_new_key_to_identity (4 tests) + // ------------------------------------------------- #[test] - fn should_add_one_new_key_to_identity() { - let drive = setup_drive_with_initial_state_structure(None); + fn should_add_one_new_key_to_identity_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 14202000, + processing_fee: 1098260, + ..Default::default() + }; + + do_should_add_one_new_key_to_identity(true, platform_version, expected_fee_result); + } + #[test] + fn should_add_one_new_key_to_identity_first_version_estimated() { let platform_version = PlatformVersion::first(); + // Adjust the expected processing_fee if it differs from "apply = true" + // or as needed for your scenario + let expected_fee_result = FeeResult { + storage_fee: 17145000, + processing_fee: 5483620, + ..Default::default() + }; + + do_should_add_one_new_key_to_identity(false, platform_version, expected_fee_result); + } + + #[test] + fn should_add_one_new_key_to_identity_latest_version_apply() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 14202000, + processing_fee: 1098260, + ..Default::default() + }; + + do_should_add_one_new_key_to_identity(true, platform_version, expected_fee_result); + } + + #[test] + fn should_add_one_new_key_to_identity_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 17145000, + processing_fee: 5483620, + ..Default::default() + }; + + do_should_add_one_new_key_to_identity(false, platform_version, expected_fee_result); + } + + fn do_should_add_one_new_key_to_identity( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); 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()); + // We assume the user wants to apply or just estimate for adding identity drive .add_new_identity( identity.clone(), false, &block, - true, + apply, None, platform_version, ) @@ -51,39 +110,90 @@ mod tests { identity.id().to_buffer(), new_keys_to_add, &block, - true, + apply, Some(&db_transaction), platform_version, ) .expect("expected to update identity with new keys"); - assert_eq!( - fee_result, - FeeResult { - storage_fee: 14202000, - processing_fee: 1098260, - ..Default::default() - } - ); + assert_eq!(fee_result, expected_fee_result); + + if apply { + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + + let identity_keys = drive + .fetch_all_identity_keys(identity.id().to_buffer(), None, platform_version) + .expect("expected to get keys"); + assert_eq!(identity_keys.len(), 6); // we had 5 keys and we added 1 + } else { + // Not applying -> no commit. We can check root hash if we want + let app_hash_after = drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .unwrap() + .expect("should return app hash"); + // Or any other logic to ensure no state changes actually took effect + let _ = app_hash_after; + } + } - drive - .grove - .commit_transaction(db_transaction) - .unwrap() - .expect("expected to be able to commit a transaction"); + // ------------------------------------------------- + // check_reference_below_tokens_cost (4 tests) + // ------------------------------------------------- + #[test] + fn check_reference_below_tokens_cost_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 9423000, + processing_fee: 406100, + ..Default::default() + }; + do_check_reference_below_tokens_cost(true, platform_version, expected_fee_result); + } - let identity_keys = drive - .fetch_all_identity_keys(identity.id().to_buffer(), None, platform_version) - .expect("expected to get balance"); + #[test] + fn check_reference_below_tokens_cost_first_version_estimated() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 9423000, + processing_fee: 314560, + ..Default::default() + }; + do_check_reference_below_tokens_cost(false, platform_version, expected_fee_result); + } - assert_eq!(identity_keys.len(), 6); // we had 5 keys and we added 1 + #[test] + fn check_reference_below_tokens_cost_latest_version_apply() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 9423000, + processing_fee: 406100, + ..Default::default() + }; + do_check_reference_below_tokens_cost(true, platform_version, expected_fee_result); } #[test] - fn should_add_two_dozen_new_keys_to_identity() { - let drive = setup_drive_with_initial_state_structure(None); + fn check_reference_below_tokens_cost_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 9423000, + processing_fee: 314560, + ..Default::default() + }; + do_check_reference_below_tokens_cost(false, platform_version, expected_fee_result); + } - let platform_version = PlatformVersion::first(); + fn do_check_reference_below_tokens_cost( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -95,97 +205,186 @@ mod tests { identity.clone(), false, &block, - true, + apply, None, platform_version, ) .expect("expected to insert identity"); - let new_keys_to_add = - IdentityPublicKey::random_authentication_keys(5, 24, Some(15), platform_version); + IdentityPublicKey::random_authentication_keys(5, 1, Some(15), platform_version); + + let mut rng = StdRng::seed_from_u64(23450); let db_transaction = drive.grove.start_transaction(); - let fee_result = drive - .add_new_unique_keys_to_identity( + let batch_operations = drive + .insert_non_unique_public_key_hash_reference_to_identity_operations( identity.id().to_buffer(), - new_keys_to_add, - &block, - true, + rng.gen(), + &mut None, Some(&db_transaction), - platform_version, + &platform_version.drive, ) .expect("expected to update identity with new keys"); - assert_eq!( - fee_result, - FeeResult { - storage_fee: 347382000, - processing_fee: 6819220, - ..Default::default() - } - ); - + let mut drive_operations: Vec = vec![]; drive - .grove - .commit_transaction(db_transaction) - .unwrap() - .expect("expected to be able to commit a transaction"); + .apply_batch_low_level_drive_operations( + None, + Some(&db_transaction), + batch_operations, + &mut drive_operations, + &platform_version.drive, + ) + .expect("expected to apply operations"); + + let fee_result = Drive::calculate_fee( + None, + Some(drive_operations), + &Epoch::new(0).unwrap(), + drive.config.epochs_per_era, + platform_version, + None, + ) + .expect("expected fee result"); + + assert_eq!(fee_result, expected_fee_result); + + if apply { + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + } else { + // Not applying -> no commit + } + } - let identity_keys = drive - .fetch_all_identity_keys(identity.id().to_buffer(), None, platform_version) - .expect("expected to get balance"); + // ------------------------------------------------- + // should_add_two_dozen_new_keys_to_identity (4 tests) + // ------------------------------------------------- + #[test] + fn should_add_two_dozen_new_keys_to_identity_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 347382000, + processing_fee: 6819220, + ..Default::default() + }; + + do_should_add_two_dozen_new_keys_to_identity( + true, + platform_version, + expected_fee_result, + ); + } - assert_eq!(identity_keys.len(), 29); // we had 5 keys and we added 24 + #[test] + fn should_add_two_dozen_new_keys_to_identity_first_version_estimated() { + let platform_version = PlatformVersion::first(); + // Possibly different processing fee if "estimated" differs + let expected_fee_result = FeeResult { + storage_fee: 356211000, + processing_fee: 11699520, + ..Default::default() + }; + + do_should_add_two_dozen_new_keys_to_identity( + false, + platform_version, + expected_fee_result, + ); } #[test] - fn should_estimated_costs_without_state() { - let drive = setup_drive_with_initial_state_structure(None); + fn should_add_two_dozen_new_keys_to_identity_latest_version_apply() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 347382000, + processing_fee: 6819220, + ..Default::default() + }; + + do_should_add_two_dozen_new_keys_to_identity( + true, + platform_version, + expected_fee_result, + ); + } - let platform_version = PlatformVersion::first(); + #[test] + fn should_add_two_dozen_new_keys_to_identity_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 356211000, + processing_fee: 11699520, + ..Default::default() + }; + + do_should_add_two_dozen_new_keys_to_identity( + false, + platform_version, + expected_fee_result, + ); + } + + fn do_should_add_two_dozen_new_keys_to_identity( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); 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()); + drive + .add_new_identity( + identity.clone(), + false, + &block, + apply, + None, + platform_version, + ) + .expect("expected to insert identity"); + let new_keys_to_add = - IdentityPublicKey::random_authentication_keys(5, 1, Some(15), platform_version); + IdentityPublicKey::random_authentication_keys(5, 24, Some(15), platform_version); - let app_hash_before = drive - .grove - .root_hash(None, &platform_version.drive.grove_version) - .unwrap() - .expect("should return app hash"); + let db_transaction = drive.grove.start_transaction(); let fee_result = drive .add_new_unique_keys_to_identity( identity.id().to_buffer(), new_keys_to_add, &block, - false, - None, + apply, + Some(&db_transaction), platform_version, ) .expect("expected to update identity with new keys"); - let app_hash_after = drive - .grove - .root_hash(None, &platform_version.drive.grove_version) - .unwrap() - .expect("should return app hash"); + assert_eq!(fee_result, expected_fee_result); - assert_eq!(app_hash_after, app_hash_before); + if apply { + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); - assert_eq!( - fee_result, - FeeResult { - storage_fee: 17145000, - processing_fee: 5483620, - ..Default::default() - } - ); + let identity_keys = drive + .fetch_all_identity_keys(identity.id().to_buffer(), None, platform_version) + .expect("expected to get balance"); + + assert_eq!(identity_keys.len(), 29); // we had 5 keys, added 24 + } else { + // Not applying => no commit + } } } @@ -198,11 +397,59 @@ mod tests { use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dpp::version::PlatformVersion; + // ------------------------------------------------- + // should_disable_a_few_keys (4 tests) + // ------------------------------------------------- #[test] - fn should_disable_a_few_keys() { - let drive = setup_drive_with_initial_state_structure(None); + fn should_disable_a_few_keys_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 513000, + processing_fee: 869380, + ..Default::default() + }; + do_should_disable_a_few_keys(true, platform_version, expected_fee_result); + } + #[test] + fn should_disable_a_few_keys_first_version_estimated() { let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 486000, + processing_fee: 3216860, + ..Default::default() + }; + do_should_disable_a_few_keys(false, platform_version, expected_fee_result); + } + + #[test] + fn should_disable_a_few_keys_latest_version_apply() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 513000, + processing_fee: 869380, + ..Default::default() + }; + do_should_disable_a_few_keys(true, platform_version, expected_fee_result); + } + + #[test] + fn should_disable_a_few_keys_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 486000, + processing_fee: 3216860, + ..Default::default() + }; + do_should_disable_a_few_keys(false, platform_version, expected_fee_result); + } + + fn do_should_disable_a_few_keys( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -245,92 +492,78 @@ mod tests { key_ids, disable_at, &block_info, - true, + apply, Some(&db_transaction), platform_version, ) .expect("should disable a few keys"); - assert_eq!( - fee_result, - FeeResult { - storage_fee: 513000, - processing_fee: 869380, - ..Default::default() - } - ); - - drive - .grove - .commit_transaction(db_transaction) - .unwrap() - .expect("expected to be able to commit a transaction"); + assert_eq!(fee_result, expected_fee_result); - let identity_keys = drive - .fetch_all_identity_keys(identity.id().to_buffer(), None, platform_version) - .expect("expected to get balance"); + if apply { + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to commit transaction"); - assert_eq!(identity_keys.len(), 7); // we had 5 keys and we added 2 + let identity_keys = drive + .fetch_all_identity_keys(identity.id().to_buffer(), None, platform_version) + .expect("expected to get balance"); - for (_, key) in identity_keys.into_iter().skip(5) { - assert_eq!(key.disabled_at(), Some(disable_at)); + assert_eq!(identity_keys.len(), 7); // we had 5 keys and we added 2 + for (_, key) in identity_keys.into_iter().skip(5) { + assert_eq!(key.disabled_at(), Some(disable_at)); + } } } #[test] - fn should_estimated_costs_without_state() { - let drive = setup_drive_with_initial_state_structure(None); - + fn estimated_costs_should_have_same_storage_cost_first_version() { let platform_version = PlatformVersion::first(); - - let identity = Identity::random_identity(5, Some(12345), platform_version) - .expect("expected a random identity"); - - let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); - - let disable_at = Utc::now().timestamp_millis() as TimestampMillis; - - let app_hash_before = drive - .grove - .root_hash(None, &platform_version.drive.grove_version) - .unwrap() - .expect("should return app hash"); - - let fee_result = drive - .disable_identity_keys( - identity.id().to_buffer(), - vec![0, 1], - disable_at, - &block_info, - false, - None, - platform_version, - ) - .expect("should estimate the disabling of a few keys"); - - 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 { - storage_fee: 486000, - processing_fee: 3216860, - ..Default::default() - } + let expected_estimated_fee_result = FeeResult { + storage_fee: 486000, + processing_fee: 3216860, + ..Default::default() + }; + let expected_fee_result = FeeResult { + storage_fee: 486000, + processing_fee: 794720, + ..Default::default() + }; + estimated_costs_should_have_same_storage_cost( + platform_version, + expected_estimated_fee_result, + expected_fee_result, ); } #[test] - fn estimated_costs_should_have_same_storage_cost() { - let drive = setup_drive_with_initial_state_structure(None); + fn estimated_costs_should_have_same_storage_cost_latest_version() { + let platform_version = PlatformVersion::latest(); + let expected_estimated_fee_result = FeeResult { + storage_fee: 486000, + processing_fee: 3216860, + ..Default::default() + }; + let expected_fee_result = FeeResult { + storage_fee: 486000, + processing_fee: 794720, + ..Default::default() + }; + estimated_costs_should_have_same_storage_cost( + platform_version, + expected_estimated_fee_result, + expected_fee_result, + ); + } - let platform_version = PlatformVersion::first(); + fn estimated_costs_should_have_same_storage_cost( + platform_version: &PlatformVersion, + expected_estimated_fee_result: FeeResult, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); @@ -350,7 +583,7 @@ mod tests { let disable_at = Utc::now().timestamp_millis() as TimestampMillis; - let expected_fee_result = drive + let estimated_fee_result = drive .disable_identity_keys( identity.id().to_buffer(), vec![0, 1], @@ -374,7 +607,9 @@ mod tests { ) .expect("should get the cost of the disabling a few keys"); - assert_eq!(expected_fee_result.storage_fee, fee_result.storage_fee); + assert_eq!(estimated_fee_result.storage_fee, fee_result.storage_fee); + assert_eq!(estimated_fee_result, expected_estimated_fee_result); + assert_eq!(fee_result, expected_fee_result); } } @@ -385,27 +620,87 @@ mod tests { use dpp::fee::fee_result::FeeResult; use dpp::version::PlatformVersion; + // ------------------------------------------------- + // should_update_revision (4 tests) + // ------------------------------------------------- #[test] - fn should_update_revision() { - let drive = setup_drive_with_initial_state_structure(None); + fn should_update_revision_first_version_apply() { + let platform_version = PlatformVersion::first(); + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 238820, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_update_revision(true, platform_version, expected_fee_result); + } + #[test] + fn should_update_revision_first_version_estimated() { let platform_version = PlatformVersion::first(); + // Possibly different if your scenario's estimated cost differs + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 1813560, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_update_revision(false, platform_version, expected_fee_result); + } + + #[test] + fn should_update_revision_latest_version_apply() { + let platform_version = PlatformVersion::latest(); + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 238820, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_update_revision(true, platform_version, expected_fee_result); + } + + #[test] + fn should_update_revision_latest_version_estimated() { + let platform_version = PlatformVersion::latest(); + // Possibly different if your scenario's estimated cost differs + let expected_fee_result = FeeResult { + storage_fee: 0, + processing_fee: 1813560, + removed_bytes_from_system: 0, + ..Default::default() + }; + + do_should_update_revision(false, platform_version, expected_fee_result); + } + + fn do_should_update_revision( + apply: bool, + platform_version: &PlatformVersion, + expected_fee_result: FeeResult, + ) { + let drive = setup_drive_with_initial_state_structure(None); let identity = Identity::random_identity(5, Some(12345), platform_version) .expect("expected a random identity"); let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); + // Insert identity drive .add_new_identity( identity.clone(), false, &block_info, - true, + apply, None, platform_version, ) .expect("expected to insert identity"); + // We'll update the revision from 0 -> 2 let revision = 2; let db_transaction = drive.grove.start_transaction(); @@ -415,84 +710,35 @@ mod tests { identity.id().to_buffer(), revision, &block_info, - true, + apply, Some(&db_transaction), platform_version, None, ) .expect("should update revision"); - assert_eq!( - fee_result, - FeeResult { - storage_fee: 0, - processing_fee: 238820, - removed_bytes_from_system: 0, - ..Default::default() - } - ); - - drive - .grove - .commit_transaction(db_transaction) - .unwrap() - .expect("expected to be able to commit a transaction"); - - let updated_revision = drive - .fetch_identity_revision(identity.id().to_buffer(), true, None, platform_version) - .expect("expected to get revision"); - - assert_eq!(updated_revision, Some(revision)); - } - - #[test] - fn should_estimated_costs_without_state() { - let drive = setup_drive_with_initial_state_structure(None); - - let platform_version = PlatformVersion::first(); - - let identity = Identity::random_identity(5, Some(12345), platform_version) - .expect("expected a random identity"); - - let block_info = BlockInfo::default_with_epoch(Epoch::new(0).unwrap()); - - let revision = 2; - - let app_hash_before = drive - .grove - .root_hash(None, &platform_version.drive.grove_version) - .unwrap() - .expect("should return app hash"); - - let fee_result = drive - .update_identity_revision( - identity.id().to_buffer(), - revision, - &block_info, - false, - None, - platform_version, - None, - ) - .expect("should estimate the revision update"); - - 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 { - storage_fee: 0, - processing_fee: 1813560, - removed_bytes_from_system: 0, - ..Default::default() - } - ); + assert_eq!(fee_result, expected_fee_result); + + if apply { + drive + .grove + .commit_transaction(db_transaction) + .unwrap() + .expect("expected to be able to commit a transaction"); + + // check new revision + let updated_revision = drive + .fetch_identity_revision( + identity.id().to_buffer(), + true, + None, + platform_version, + ) + .expect("expected to get revision"); + assert_eq!(updated_revision, Some(revision)); + } else { + // No commit => no changes + } } } } diff --git a/packages/rs-drive/src/drive/mod.rs b/packages/rs-drive/src/drive/mod.rs index fc28c49647a..e54d5445a2d 100644 --- a/packages/rs-drive/src/drive/mod.rs +++ b/packages/rs-drive/src/drive/mod.rs @@ -42,7 +42,10 @@ pub mod system; mod asset_lock; #[cfg(feature = "server")] mod platform_state; -pub(crate) mod prefunded_specialized_balances; + +/// Prefunded specialized balances module +#[cfg(any(feature = "server", feature = "verify"))] +pub mod prefunded_specialized_balances; /// Vote module #[cfg(any(feature = "server", feature = "verify"))] diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/mod.rs index 18fd27d1039..4a02d9e9c67 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -50,9 +51,16 @@ impl Drive { transaction, platform_version, ), + 1 => self.add_prefunded_specialized_balance_operations_v1( + specialized_balance_id, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "add_prefunded_specialized_balance_operations".to_string(), - known_versions: vec![0], + known_versions: vec![0, 1], received: version, })), } 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 new file mode 100644 index 00000000000..6a462649495 --- /dev/null +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/add_prefunded_specialized_balance_operations/v1/mod.rs @@ -0,0 +1,91 @@ +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 crate::drive::prefunded_specialized_balances::{ + prefunded_specialized_balances_for_voting_path, + prefunded_specialized_balances_for_voting_path_vec, +}; +use crate::error::identity::IdentityError; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +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 std::collections::HashMap; + +impl Drive { + /// The operations to add to the specialized balance + #[inline(always)] + pub(super) fn add_prefunded_specialized_balance_operations_v1( + &self, + specialized_balance_id: Identifier, + amount: u64, + 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_prefunded_specialized_balance_update( + 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_using_sums: true, + query_target: QueryTargetValue(8), + } + }; + + let path_holding_specialized_balances = prefunded_specialized_balances_for_voting_path(); + let previous_credits_in_specialized_balance = self + .grove_get_raw_value_u64_from_encoded_var_vec( + (&path_holding_specialized_balances).into(), + specialized_balance_id.as_slice(), + direct_query_type, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + let had_previous_balance = previous_credits_in_specialized_balance.is_some(); + let new_total = previous_credits_in_specialized_balance + .unwrap_or_default() + .checked_add(amount) + .ok_or(Error::Drive(DriveError::CriticalCorruptedState( + "trying to add an amount that would overflow credits", + )))?; + // while i64::MAX could potentially work, best to avoid it. + if new_total >= MAX_CREDITS { + return Err(Error::Identity(IdentityError::CriticalBalanceOverflow( + "trying to set prefunded specialized balance to over max credits amount (i64::MAX)", + ))); + }; + let path_holding_total_credits_vec = prefunded_specialized_balances_for_voting_path_vec(); + let op = if had_previous_balance { + QualifiedGroveDbOp::replace_op( + path_holding_total_credits_vec, + specialized_balance_id.to_vec(), + Element::new_sum_item(new_total as i64), + ) + } else { + QualifiedGroveDbOp::insert_or_replace_op( + path_holding_total_credits_vec, + specialized_balance_id.to_vec(), + Element::new_sum_item(new_total as i64), + ) + }; + drive_operations.push(GroveOperation(op)); + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/mod.rs index d294ec90872..aef16a0cb53 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/mod.rs @@ -1,4 +1,5 @@ mod v0; +mod v1; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -50,6 +51,13 @@ impl Drive { transaction, platform_version, ), + 1 => self.deduct_from_prefunded_specialized_balance_operations_v1( + specialized_balance_id, + amount, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "deduct_from_prefunded_specialized_balance_operations".to_string(), known_versions: vec![0], 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 new file mode 100644 index 00000000000..4bf03c848ff --- /dev/null +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/deduct_from_prefunded_specialized_balance_operations/v1/mod.rs @@ -0,0 +1,91 @@ +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 crate::drive::prefunded_specialized_balances::{ + prefunded_specialized_balances_for_voting_path, + prefunded_specialized_balances_for_voting_path_vec, +}; +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 std::collections::HashMap; + +impl Drive { + /// The operations to add to the specialized balance + #[inline(always)] + pub(super) fn deduct_from_prefunded_specialized_balance_operations_v1( + &self, + specialized_balance_id: Identifier, + amount: u64, + 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_prefunded_specialized_balance_update( + 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_using_sums: true, + query_target: QueryTargetValue(8), + } + }; + + let path_holding_specialized_balances = prefunded_specialized_balances_for_voting_path(); + let previous_credits_in_specialized_balance = match self + .grove_get_raw_value_u64_from_encoded_var_vec( + (&path_holding_specialized_balances).into(), + specialized_balance_id.as_slice(), + direct_query_type, + transaction, + &mut drive_operations, + &platform_version.drive, + )? { + None => { + if estimated_costs_only_with_layer_info.is_none() { + return + Err(Error::Drive( + DriveError::PrefundedSpecializedBalanceDoesNotExist(format!( + "trying to deduct from a prefunded specialized balance {} that does not exist", + specialized_balance_id + )), + )); + } else { + i64::MAX as u64 + } + } + Some(value) => value, + }; + let new_total = previous_credits_in_specialized_balance + .checked_sub(amount) + .ok_or(Error::Drive( + DriveError::PrefundedSpecializedBalanceNotEnough( + previous_credits_in_specialized_balance, + amount, + ), + ))?; + let path_holding_total_credits_vec = prefunded_specialized_balances_for_voting_path_vec(); + let replace_op = QualifiedGroveDbOp::replace_op( + path_holding_total_credits_vec, + specialized_balance_id.to_vec(), + Element::new_sum_item(new_total as i64), + ); + drive_operations.push(GroveOperation(replace_op)); + Ok(drive_operations) + } +} diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance/mod.rs new file mode 100644 index 00000000000..acf43841664 --- /dev/null +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance/mod.rs @@ -0,0 +1,53 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; + +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Empties from a prefunded specialized balance the entire left over balance + /// + /// # Arguments + /// + /// * `transaction` - A `TransactionArg` object representing the transaction to be used for adding to the system credits. + /// * `platform_version` - A `PlatformVersion` object specifying the version of Platform. + /// + /// # Returns + /// + /// * `Result<(), Error>` - If successful, returns `Ok(())`. If an error occurs during the operation, returns an `Error`. + /// + /// # Errors + /// + /// This function will return an error if the version of Platform is unknown. + pub fn empty_prefunded_specialized_balance( + &self, + specialized_balance_id: Identifier, + error_if_does_not_exist: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .prefunded_specialized_balances + .empty_prefunded_specialized_balance + { + 0 => self.empty_prefunded_specialized_balance_v0( + specialized_balance_id, + error_if_does_not_exist, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "empty_prefunded_specialized_balance".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance/v0/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance/v0/mod.rs new file mode 100644 index 00000000000..4e46151f5f3 --- /dev/null +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance/v0/mod.rs @@ -0,0 +1,52 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; + +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Empties the prefunded specialized balance + /// + /// # Arguments + /// + /// * `transaction` - A `TransactionArg` object representing the transaction to be used for adding to the system credits. + /// * `platform_version` - A `PlatformVersion` object specifying the version of Platform. + /// + /// # Returns + /// + /// * `Result<(), Error>` - If successful, returns `Ok(())`. If an error occurs during the operation, returns an `Error`. + /// + /// # Errors + /// + /// This function will return an error if the version of Platform is unknown. + #[inline(always)] + pub(super) fn empty_prefunded_specialized_balance_v0( + &self, + specialized_balance_id: Identifier, + error_if_does_not_exist: bool, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let mut drive_operations = vec![]; + let (credits, batch_operations) = self.empty_prefunded_specialized_balance_operations( + specialized_balance_id, + error_if_does_not_exist, + &mut None, + transaction, + platform_version, + )?; + let grove_db_operations = + LowLevelDriveOperation::grovedb_operations_batch(&batch_operations); + self.grove_apply_batch_with_add_costs( + grove_db_operations, + false, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + Ok(credits) + } +} diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/mod.rs new file mode 100644 index 00000000000..d7562fac85c --- /dev/null +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/mod.rs @@ -0,0 +1,60 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::batch::KeyInfoPath; +use std::collections::HashMap; + +use crate::fees::op::LowLevelDriveOperation; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::{EstimatedLayerInformation, TransactionArg}; + +impl Drive { + /// The operation Deducts from a prefunded specialized balance it's entire amount + /// + /// # Arguments + /// + /// * `transaction` - A `TransactionArg` object representing the transaction to be used for adding to the system credits. + /// * `platform_version` - A `PlatformVersion` object specifying the version of Platform. + /// + /// # Returns + /// + /// * `Result<(), Error>` - If successful, returns `Ok(())`. If an error occurs during the operation, returns an `Error`. + /// + /// # Errors + /// + /// This function will return an error if the version of Platform is unknown. + pub fn empty_prefunded_specialized_balance_operations( + &self, + specialized_balance_id: Identifier, + error_if_does_not_exist: bool, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Credits, Vec), Error> { + match platform_version + .drive + .methods + .prefunded_specialized_balances + .empty_prefunded_specialized_balance + { + 0 => self.empty_prefunded_specialized_balance_operations_v0( + specialized_balance_id, + error_if_does_not_exist, + estimated_costs_only_with_layer_info, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "empty_prefunded_specialized_balance_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} 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 new file mode 100644 index 00000000000..c7f6b2049de --- /dev/null +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/empty_prefunded_specialized_balance_operations/v0/mod.rs @@ -0,0 +1,85 @@ +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 crate::drive::prefunded_specialized_balances::{ + prefunded_specialized_balances_for_voting_path, + prefunded_specialized_balances_for_voting_path_vec, +}; +use crate::util::grove_operations::QueryTarget::QueryTargetValue; +use dpp::fee::Credits; +use dpp::identifier::Identifier; +use dpp::version::PlatformVersion; +use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp}; +use grovedb::{EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +impl Drive { + /// The operations to add to the specialized balance + #[inline(always)] + pub(super) fn empty_prefunded_specialized_balance_operations_v0( + &self, + specialized_balance_id: Identifier, + error_if_does_not_exist: bool, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(Credits, Vec), 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_prefunded_specialized_balance_update( + 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_using_sums: true, + query_target: QueryTargetValue(8), + } + }; + + let path_holding_specialized_balances = prefunded_specialized_balances_for_voting_path(); + let previous_credits_in_specialized_balance = match self + .grove_get_raw_value_u64_from_encoded_var_vec( + (&path_holding_specialized_balances).into(), + specialized_balance_id.as_slice(), + direct_query_type, + transaction, + &mut drive_operations, + &platform_version.drive, + )? { + None => { + if estimated_costs_only_with_layer_info.is_none() { + return if error_if_does_not_exist { + Err(Error::Drive( + DriveError::PrefundedSpecializedBalanceDoesNotExist(format!( + "trying to deduct from a prefunded specialized balance {} that does not exist", + specialized_balance_id + )), + )) + } else { + Ok((0, drive_operations)) + }; + } else { + 0 + } + } + Some(value) => value, + }; + let path_holding_total_credits_vec = prefunded_specialized_balances_for_voting_path_vec(); + let delete_op = QualifiedGroveDbOp::delete_op( + path_holding_total_credits_vec, + specialized_balance_id.to_vec(), + ); + drive_operations.push(GroveOperation(delete_op)); + Ok((previous_credits_in_specialized_balance, drive_operations)) + } +} diff --git a/packages/rs-drive/src/drive/prefunded_specialized_balances/mod.rs b/packages/rs-drive/src/drive/prefunded_specialized_balances/mod.rs index 215ac249341..ea5656188c2 100644 --- a/packages/rs-drive/src/drive/prefunded_specialized_balances/mod.rs +++ b/packages/rs-drive/src/drive/prefunded_specialized_balances/mod.rs @@ -7,6 +7,10 @@ mod deduct_from_prefunded_specialized_balance; #[cfg(feature = "server")] mod deduct_from_prefunded_specialized_balance_operations; #[cfg(feature = "server")] +mod empty_prefunded_specialized_balance; +#[cfg(feature = "server")] +mod empty_prefunded_specialized_balance_operations; +#[cfg(feature = "server")] mod estimation_costs; #[cfg(feature = "server")] mod fetch; @@ -20,17 +24,18 @@ use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; #[cfg(feature = "server")] use crate::util::batch::GroveDbOpBatch; +/// The key for prefunded balances for voting pub const PREFUNDED_BALANCES_FOR_VOTING: u8 = 128; /// prefunded specialized balances for voting -pub(crate) fn prefunded_specialized_balances_path() -> [&'static [u8]; 1] { +pub fn prefunded_specialized_balances_path() -> [&'static [u8]; 1] { [Into::<&[u8; 1]>::into( RootTree::PreFundedSpecializedBalances, )] } /// prefunded specialized balances for voting -pub(crate) fn prefunded_specialized_balances_for_voting_path() -> [&'static [u8]; 2] { +pub fn prefunded_specialized_balances_for_voting_path() -> [&'static [u8]; 2] { [ Into::<&[u8; 1]>::into(RootTree::PreFundedSpecializedBalances), &[PREFUNDED_BALANCES_FOR_VOTING], @@ -38,7 +43,7 @@ pub(crate) fn prefunded_specialized_balances_for_voting_path() -> [&'static [u8] } /// prefunded specialized balances for voting vector -pub(crate) fn prefunded_specialized_balances_for_voting_path_vec() -> Vec> { +pub fn prefunded_specialized_balances_for_voting_path_vec() -> Vec> { vec![ Into::<&[u8; 1]>::into(RootTree::PreFundedSpecializedBalances).to_vec(), vec![PREFUNDED_BALANCES_FOR_VOTING], diff --git a/packages/rs-drive/src/fees/mod.rs b/packages/rs-drive/src/fees/mod.rs index 96e7c996aca..c240c54f0c9 100644 --- a/packages/rs-drive/src/fees/mod.rs +++ b/packages/rs-drive/src/fees/mod.rs @@ -2,6 +2,7 @@ use crate::error::fee::FeeError; use crate::error::Error; mod calculate_fee; +/// Operations pub mod op; /// Get overflow error diff --git a/packages/rs-drive/src/lib.rs b/packages/rs-drive/src/lib.rs index a11e8e74bd3..a13845e0fcd 100644 --- a/packages/rs-drive/src/lib.rs +++ b/packages/rs-drive/src/lib.rs @@ -41,8 +41,9 @@ pub use grovedb_storage; pub mod cache; #[cfg(any(feature = "server", feature = "verify"))] pub mod config; +/// Fees module #[cfg(feature = "server")] -mod fees; +pub mod fees; #[cfg(feature = "server")] mod open; #[cfg(feature = "server")] diff --git a/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/transformer.rs b/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/transformer.rs index 5f619841bb8..ac46cd5fda7 100644 --- a/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/transformer.rs @@ -42,3 +42,66 @@ impl IdentityCreditWithdrawalTransitionAction { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::util::test_helpers::setup::setup_drive_with_initial_state_structure; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::{Identity, IdentityPublicKey}; + use dpp::state_transition::identity_credit_withdrawal_transition::v1::IdentityCreditWithdrawalTransitionV1; + + #[test] + fn test_try_from_identity_credit_withdrawal_without_address_and_multiple_transfer_keys() { + let drive = setup_drive_with_initial_state_structure(None); + + let platform_version = PlatformVersion::latest(); + + let mut identity = Identity::random_identity(1, Some(64), &platform_version) + .expect("create random identity"); + + let (transfer_key1, _) = + IdentityPublicKey::random_masternode_transfer_key(2, Some(64), &platform_version) + .expect("create random masternode transfer key"); + let (transfer_key2, _) = + IdentityPublicKey::random_masternode_transfer_key(3, Some(64), &platform_version) + .expect("create random masternode transfer key"); + + identity.add_public_keys([transfer_key1, transfer_key2]); + + let identity_id = identity.id(); + + drive + .add_new_identity( + identity, + true, + &BlockInfo::default(), + true, + None, + platform_version, + ) + .expect("create new identity"); + + let transition = + IdentityCreditWithdrawalTransition::V1(IdentityCreditWithdrawalTransitionV1 { + identity_id, + nonce: 0, + amount: 0, + core_fee_per_byte: 0, + pooling: Default::default(), + output_script: None, + user_fee_increase: 0, + signature_public_key_id: 0, + signature: Default::default(), + }); + + IdentityCreditWithdrawalTransitionAction::try_from_identity_credit_withdrawal( + &drive, + None, + &transition, + &BlockInfo::default(), + platform_version, + ) + .expect("create action"); + } +} diff --git a/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/v0/transformer.rs index e2c443d9ab7..bf4f38b651a 100644 --- a/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/identity/identity_credit_withdrawal/v0/transformer.rs @@ -93,7 +93,7 @@ impl IdentityCreditWithdrawalTransitionActionV0 { let key_request = IdentityKeysRequest { identity_id: identity_credit_withdrawal.identity_id.to_buffer(), request_type: KeyRequestType::RecentWithdrawalKeys, - limit: None, + limit: Some(1), offset: None, }; let key: Option = @@ -177,7 +177,7 @@ impl IdentityCreditWithdrawalTransitionActionV0 { let withdrawal_document = DocumentV0 { id: document_id, owner_id: identity_credit_withdrawal.identity_id, - properties: document_data.into_btree_string_map().unwrap(), + properties: document_data.into_btree_string_map()?, revision: Some(1), created_at: Some(block_info.time_ms), updated_at: Some(block_info.time_ms), 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 9b9a5be3bbb..9c8f567fa9a 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 @@ -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_optional_v0>( + pub(super) fn grove_get_raw_optional_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 41736ed442e..8178d007b2d 100644 --- a/packages/rs-drive/src/util/grove_operations/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/mod.rs @@ -221,7 +221,7 @@ pub enum BatchDeleteUpTreeApplyType { /// Stateless batch delete StatelessBatchDelete { /// The estimated layer info - estimated_layer_info: IntMap, + estimated_layer_info: IntMap, }, /// Stateful batch delete StatefulBatchDelete { diff --git a/packages/rs-json-schema-compatibility-validator/Cargo.toml b/packages/rs-json-schema-compatibility-validator/Cargo.toml index aa4763a2560..a4211f6d181 100644 --- a/packages/rs-json-schema-compatibility-validator/Cargo.toml +++ b/packages/rs-json-schema-compatibility-validator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "json-schema-compatibility-validator" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true authors = ["Ivan Shumkov "] diff --git a/packages/rs-platform-serialization-derive/Cargo.toml b/packages/rs-platform-serialization-derive/Cargo.toml index 1017408832d..ea275283925 100644 --- a/packages/rs-platform-serialization-derive/Cargo.toml +++ b/packages/rs-platform-serialization-derive/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-serialization-derive" authors = ["Samuel Westrich "] description = "Bincode serialization and deserialization derivations" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-platform-serialization/Cargo.toml b/packages/rs-platform-serialization/Cargo.toml index 8b58f6b878c..6a4e6f586c6 100644 --- a/packages/rs-platform-serialization/Cargo.toml +++ b/packages/rs-platform-serialization/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-serialization" authors = ["Samuel Westrich "] description = "Bincode based serialization and deserialization" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-platform-value-convertible/Cargo.toml b/packages/rs-platform-value-convertible/Cargo.toml index f518e7b341e..dacf12b51f8 100644 --- a/packages/rs-platform-value-convertible/Cargo.toml +++ b/packages/rs-platform-value-convertible/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-value-convertible" authors = ["Samuel Westrich "] description = "Convertion to and from platform values" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-platform-value/Cargo.toml b/packages/rs-platform-value/Cargo.toml index bbb11d7b775..c8781a258f5 100644 --- a/packages/rs-platform-value/Cargo.toml +++ b/packages/rs-platform-value/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-value" authors = ["Samuel Westrich "] description = "A simple value module" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-platform-value/src/inner_value.rs b/packages/rs-platform-value/src/inner_value.rs index c92828e91c0..d8606bd478b 100644 --- a/packages/rs-platform-value/src/inner_value.rs +++ b/packages/rs-platform-value/src/inner_value.rs @@ -361,7 +361,7 @@ impl Value { Self::inner_array_mut_ref(map, key) } - pub fn get_array_slice<'a>(&'a self, key: &'a str) -> Result<&[Value], Error> { + pub fn get_array_slice<'a>(&'a self, key: &'a str) -> Result<&'a [Value], Error> { let map = self.to_map()?; Self::inner_array_slice(map, key) } diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 1ad05c6401b..308329b22a8 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-version" authors = ["Samuel Westrich "] description = "Versioning library for Platform" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" @@ -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.1.0" } +grovedb-version = { version = "2.2.1" } once_cell = "1.19.0" [features] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_method_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_method_versions/mod.rs index a39362f90ec..e541023efc6 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_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 DPPMethodVersions { diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_method_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_method_versions/v2.rs new file mode 100644 index 00000000000..d15ed3eaaf2 --- /dev/null +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_method_versions/v2.rs @@ -0,0 +1,5 @@ +use crate::version::dpp_versions::dpp_method_versions::DPPMethodVersions; +pub const DPP_METHOD_VERSIONS_V2: DPPMethodVersions = DPPMethodVersions { + epoch_core_reward_credits_for_distribution: 0, + daily_withdrawal_limit: 1, +}; 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 48caab4b3ca..8d671176f41 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 @@ -4,6 +4,7 @@ pub mod v1; pub mod v2; pub mod v3; pub mod v4; +pub mod v5; #[derive(Clone, Debug, Default)] pub struct DriveAbciMethodVersions { 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 new file mode 100644 index 00000000000..8b9e7b1eae7 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs @@ -0,0 +1,125 @@ +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, DriveAbciVotingMethodVersions, +}; + +pub const DRIVE_ABCI_METHOD_VERSIONS_V5: 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: 0, + }, + 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: 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, + // We changed `pool_withdrawals_into_transactions_queue` to v1 in order to add pool + // withdrawals on any validator quorums. v0 allowed us to pool only on the first two + // quorums as workaround for Core v21 bug. + pool_withdrawals_into_transactions_queue: 1, + update_broadcasted_withdrawal_statuses: 0, + // Rebroadcasting should also no longer use the first two quorums only + 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_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index 4bd5ff6269c..71d54cdb7c1 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 @@ -2,6 +2,7 @@ pub mod v1; pub mod v2; pub mod v3; pub mod v4; +pub mod v5; use versioned_feature_core::{FeatureVersion, OptionalFeatureVersion}; 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 ff70d44107d..8a1659106de 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 @@ -6,6 +6,9 @@ use crate::version::drive_abci_versions::drive_abci_validation_versions::{ DriveAbciValidationVersions, PenaltyAmounts, }; +// We introduced nonce validation for masternode voting in this version, and changed the call +// for nonce validation, however the actual validation for masternode voting was faulty, which is +// why we introduced V5. (We also are making an emergency hard fork). pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = DriveAbciValidationVersions { state_transitions: DriveAbciStateTransitionValidationVersions { @@ -131,7 +134,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = document_update_price_transition_state_validation: 0, }, }, - has_nonce_validation: 1, + has_nonce_validation: 1, // <---- changed this process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { 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 new file mode 100644 index 00000000000..d48857faba9 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -0,0 +1,151 @@ +use crate::version::drive_abci_versions::drive_abci_validation_versions::{ + DriveAbciAssetLockValidationVersions, DriveAbciDocumentsStateTransitionValidationVersions, + DriveAbciStateTransitionCommonValidationVersions, DriveAbciStateTransitionValidationVersion, + DriveAbciStateTransitionValidationVersions, DriveAbciValidationConstants, + DriveAbciValidationDataTriggerAndBindingVersions, DriveAbciValidationDataTriggerVersions, + DriveAbciValidationVersions, PenaltyAmounts, +}; + +// In this version we change the nonce validation of masternode voting. +// There was a bug before this where the nonce validation would validate using the owner identity +// instead of the voting identity. +// This is not the same issue as before when we didn't validate nonces on masternode votes at all. +pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = + DriveAbciValidationVersions { + state_transitions: DriveAbciStateTransitionValidationVersions { + common_validation_methods: DriveAbciStateTransitionCommonValidationVersions { + asset_locks: DriveAbciAssetLockValidationVersions { + fetch_asset_lock_transaction_output_sync: 0, + verify_asset_lock_is_not_spent_and_has_enough_balance: 0, + }, + validate_identity_public_key_contract_bounds: 0, + validate_identity_public_key_ids_dont_exist_in_state: 0, + validate_identity_public_key_ids_exist_in_state: 0, + validate_state_transition_identity_signed: 0, + validate_unique_identity_public_key_hashes_in_state: 0, + validate_master_key_uniqueness: 0, + validate_simple_pre_check_balance: 0, + }, + max_asset_lock_usage_attempts: 16, + identity_create_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: Some(0), + identity_signatures: Some(0), + advanced_minimum_balance_pre_check: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + identity_update_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: Some(0), + identity_signatures: Some(0), + advanced_minimum_balance_pre_check: None, + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + identity_top_up_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + identity_credit_withdrawal_state_transition: + DriveAbciStateTransitionValidationVersion { + basic_structure: Some(1), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: Some(0), + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0, + identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: Some(0), + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + masternode_vote_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: Some(0), + identity_signatures: None, + advanced_minimum_balance_pre_check: Some(0), + nonce: Some(1), // <---- Changed this here + state: 0, + transform_into_action: 0, + }, + contract_create_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: None, + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + contract_update_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + advanced_minimum_balance_pre_check: None, + nonce: Some(0), + state: 0, + transform_into_action: 0, + }, + documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions { + balance_pre_check: 0, + basic_structure: 0, + advanced_structure: 0, + state: 0, + revision: 0, + transform_into_action: 0, + data_triggers: DriveAbciValidationDataTriggerAndBindingVersions { + bindings: 0, + triggers: DriveAbciValidationDataTriggerVersions { + create_contact_request_data_trigger: 0, + create_domain_data_trigger: 0, + create_identity_data_trigger: 0, + create_feature_flag_data_trigger: 0, + create_masternode_reward_shares_data_trigger: 0, + delete_withdrawal_data_trigger: 0, + reject_data_trigger: 0, + }, + }, + is_allowed: 0, + document_create_transition_structure_validation: 0, + document_delete_transition_structure_validation: 0, + document_replace_transition_structure_validation: 0, + document_transfer_transition_structure_validation: 0, + document_purchase_transition_structure_validation: 0, + document_update_price_transition_structure_validation: 0, + document_create_transition_state_validation: 1, + document_delete_transition_state_validation: 0, + document_replace_transition_state_validation: 0, + document_transfer_transition_state_validation: 0, + document_purchase_transition_state_validation: 0, + document_update_price_transition_state_validation: 0, + }, + }, + has_nonce_validation: 1, + process_state_transition: 0, + state_transition_to_execution_event_for_check_tx: 0, + penalties: PenaltyAmounts { + identity_id_not_correct: 50000000, + unique_key_already_present: 10000000, + validation_of_added_keys_structure_failure: 10000000, + validation_of_added_keys_proof_of_possession_failure: 50000000, + }, + event_constants: DriveAbciValidationConstants { + maximum_vote_polls_to_process: 2, + maximum_contenders_to_consider: 100, + }, + }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/mod.rs index 0d116b4104a..4e60e2c417d 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/mod.rs @@ -28,6 +28,7 @@ pub struct DriveCreditPoolEpochsMethodVersions { pub get_epochs_proposer_block_count: FeatureVersion, pub add_update_pending_epoch_refunds_operations: FeatureVersion, pub is_epochs_proposers_tree_empty: FeatureVersion, + pub add_epoch_processing_credits_for_distribution_operation: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/v1.rs index 43117298860..7c2252edfb8 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_credit_pool_method_versions/v1.rs @@ -25,6 +25,7 @@ pub const CREDIT_POOL_METHOD_VERSIONS_V1: DriveCreditPoolMethodVersions = get_epochs_proposer_block_count: 0, add_update_pending_epoch_refunds_operations: 0, is_epochs_proposers_tree_empty: 0, + add_epoch_processing_credits_for_distribution_operation: 0, }, pending_epoch_refunds: DriveCreditPoolPendingEpochRefundsMethodVersions { add_delete_pending_epoch_refunds_except_specified: 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 b8c3fae487d..262ac9407a3 100644 --- a/packages/rs-platform-version/src/version/drive_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/mod.rs @@ -21,6 +21,7 @@ pub mod drive_verify_method_versions; pub mod drive_vote_method_versions; pub mod v1; pub mod v2; +pub mod v3; #[derive(Clone, Debug, Default)] pub struct DriveVersion { @@ -85,6 +86,7 @@ pub struct DrivePrefundedSpecializedMethodVersions { pub deduct_from_prefunded_specialized_balance: FeatureVersion, pub deduct_from_prefunded_specialized_balance_operations: FeatureVersion, pub estimated_cost_for_prefunded_specialized_balance_update: FeatureVersion, + pub empty_prefunded_specialized_balance: FeatureVersion, } #[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 bbe1a12746f..3ba9dc974f7 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v1.rs @@ -93,6 +93,7 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { deduct_from_prefunded_specialized_balance: 0, deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, + empty_prefunded_specialized_balance: 0, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_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 5747bc732be..0881f6ca55e 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v2.rs @@ -93,6 +93,7 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { deduct_from_prefunded_specialized_balance: 0, deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, + empty_prefunded_specialized_balance: 0, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_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 new file mode 100644 index 00000000000..2f3efb37299 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/v3.rs @@ -0,0 +1,101 @@ +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_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_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::v1::GROVE_V1; + +pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { + structure: DRIVE_STRUCTURE_V1, + methods: DriveMethodVersions { + initialization: DriveInitializationMethodVersions { + create_initial_state_structure: 0, + }, + 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_V1, + 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, + 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, //changed in v3 + deduct_from_prefunded_specialized_balance: 1, //changed in v3 + deduct_from_prefunded_specialized_balance_operations: 0, + estimated_cost_for_prefunded_specialized_balance_update: 0, + empty_prefunded_specialized_balance: 0, + }, + }, + grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, + grove_version: GROVE_V1, +}; diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index 931ef19b974..e1371648ff3 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -127,6 +127,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { deduct_from_prefunded_specialized_balance: 0, deduct_from_prefunded_specialized_balance_operations: 0, estimated_cost_for_prefunded_specialized_balance_update: 0, + empty_prefunded_specialized_balance: 0, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/mod.rs b/packages/rs-platform-version/src/version/mod.rs index b143a1daf15..430317100c4 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::v7::PROTOCOL_VERSION_7; +use crate::version::v8::PROTOCOL_VERSION_8; pub use protocol_version::*; mod consensus_versions; @@ -19,8 +19,9 @@ pub mod v4; pub mod v5; pub mod v6; pub mod v7; +pub mod v8; pub type ProtocolVersion = u32; -pub const LATEST_VERSION: ProtocolVersion = PROTOCOL_VERSION_7; +pub const LATEST_VERSION: ProtocolVersion = PROTOCOL_VERSION_8; 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 d793384c729..520ceef97ad 100644 --- a/packages/rs-platform-version/src/version/protocol_version.rs +++ b/packages/rs-platform-version/src/version/protocol_version.rs @@ -22,6 +22,7 @@ use crate::version::v4::PLATFORM_V4; 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::ProtocolVersion; pub use versioned_feature_core::*; @@ -45,6 +46,7 @@ pub const PLATFORM_VERSIONS: &[PlatformVersion] = &[ PLATFORM_V5, PLATFORM_V6, PLATFORM_V7, + PLATFORM_V8, ]; #[cfg(feature = "mock-versions")] @@ -53,7 +55,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_V7; +pub const LATEST_PLATFORM_VERSION: &PlatformVersion = &PLATFORM_V8; pub const DESIRED_PLATFORM_VERSION: &PlatformVersion = LATEST_PLATFORM_VERSION; diff --git a/packages/rs-platform-version/src/version/v7.rs b/packages/rs-platform-version/src/version/v7.rs index ee532689970..0857a94ae90 100644 --- a/packages/rs-platform-version/src/version/v7.rs +++ b/packages/rs-platform-version/src/version/v7.rs @@ -16,7 +16,7 @@ use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v4::DRIVE_ABCI_METHOD_VERSIONS_V4; 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_validation_versions::v5::DRIVE_ABCI_VALIDATION_VERSIONS_V5; 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::v2::DRIVE_VERSION_V2; @@ -28,15 +28,14 @@ use crate::version::ProtocolVersion; pub const PROTOCOL_VERSION_7: ProtocolVersion = 7; -/// This version adds token support. -//todo: make changes +/// This version fixes masternode voting nonce issue. pub const PLATFORM_V7: PlatformVersion = PlatformVersion { protocol_version: PROTOCOL_VERSION_7, drive: DRIVE_VERSION_V2, drive_abci: DriveAbciVersion { structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V1, methods: DRIVE_ABCI_METHOD_VERSIONS_V4, - validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V4, + validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V5, // <--- changed to V5 withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, }, diff --git a/packages/rs-platform-version/src/version/v8.rs b/packages/rs-platform-version/src/version/v8.rs new file mode 100644 index 00000000000..7e866062157 --- /dev/null +++ b/packages/rs-platform-version/src/version/v8.rs @@ -0,0 +1,69 @@ +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::v1::CONTRACT_VERSIONS_V1; +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::v2::DPP_METHOD_VERSIONS_V2; +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::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_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::v5::DRIVE_ABCI_METHOD_VERSIONS_V5; +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::v5::DRIVE_ABCI_VALIDATION_VERSIONS_V5; +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::v3::DRIVE_VERSION_V3; +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_8: ProtocolVersion = 8; + +/// This version contains some fixes for withdrawals and nfts. +pub const PLATFORM_V8: PlatformVersion = PlatformVersion { + protocol_version: PROTOCOL_VERSION_8, + //changed to V3 because of an error in add_prefunded_specialized_balance_operations + drive: DRIVE_VERSION_V3, + drive_abci: DriveAbciVersion { + structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V1, + // We changed `pool_withdrawals_into_transactions_queue` to v1 in order to add pool + // withdrawals on any validator quorums. v0 allowed us to pool only on the first two + // quorums as workaround for Core v21 bug. + methods: DRIVE_ABCI_METHOD_VERSIONS_V5, + validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V5, + 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_V1, + 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_V1, + document_versions: DOCUMENT_VERSIONS_V1, + identity_versions: IDENTITY_VERSIONS_V1, + voting_versions: VOTING_VERSION_V2, + asset_lock_versions: DPP_ASSET_LOCK_VERSIONS_V1, + // We changed `daily_withdrawal_limit` to v1 to increase daily withdrawal limit + // to 2000 Dash. + methods: DPP_METHOD_VERSIONS_V2, + 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-platform-versioning/Cargo.toml b/packages/rs-platform-versioning/Cargo.toml index 3aa0fb87851..e2c02f7e96d 100644 --- a/packages/rs-platform-versioning/Cargo.toml +++ b/packages/rs-platform-versioning/Cargo.toml @@ -2,7 +2,7 @@ name = "platform-versioning" authors = ["Samuel Westrich "] description = "Version derivation" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index a24cd8363d7..ca37b832e56 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dash-sdk" -version = "1.7.0" +version = "1.8.0" edition = "2021" [dependencies] @@ -19,6 +19,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ drive-proof-verifier = { path = "../rs-drive-proof-verifier" } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } http = { version = "1.1" } +rustls-pemfile = { version = "2.0.0" } thiserror = "1.0.64" tokio = { version = "1.40", features = ["macros", "rt-multi-thread"] } tokio-util = { version = "0.7.12" } @@ -35,7 +36,7 @@ envy = { version = "0.4.2", optional = true } futures = { version = "0.3.30" } derive_more = { version = "1.0", features = ["from"] } # dashcore-rpc is only needed for core rpc; TODO remove once we have correct core rpc impl -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.15.13" } +dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.16.0" } lru = { version = "0.12.5", optional = true } bip37-bloom-filter = { git = "https://github.com/dashpay/rs-bip37-bloom-filter", branch = "develop" } zeroize = { version = "1.8", features = ["derive"] } @@ -55,6 +56,7 @@ tokio-test = { version = "0.4.4" } clap = { version = "4.5.4", features = ["derive"] } sanitize-filename = { version = "0.5.0" } test-case = { version = "3.3.1" } +assert_matches = "1.5.0" [features] default = ["mocks", "offline-testing"] diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index 23def69d1a9..16edd7496ce 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -88,16 +88,25 @@ impl From for Error { .metadata() .get_bin("dash-serialized-consensus-error-bin") { - return ConsensusError::deserialize_from_bytes( - consensus_error_value.as_encoded_bytes(), - ) - .map(|consensus_error| { - Self::Protocol(ProtocolError::ConsensusError(Box::new(consensus_error))) - }) - .unwrap_or_else(|e| { - tracing::debug!("Failed to deserialize consensus error: {}", e); - Self::Protocol(e) - }); + return consensus_error_value + .to_bytes() + .map(|bytes| { + ConsensusError::deserialize_from_bytes(&bytes) + .map(|consensus_error| { + Self::Protocol(ProtocolError::ConsensusError(Box::new( + consensus_error, + ))) + }) + .unwrap_or_else(|e| { + tracing::debug!("Failed to deserialize consensus error: {}", e); + Self::Protocol(e) + }) + }) + .unwrap_or_else(|e| { + tracing::debug!("Failed to deserialize consensus error: {}", e); + // TODO: Introduce a specific error for this case + Self::Generic(format!("Invalid consensus error encoding: {e}")) + }); } // Otherwise we parse the error code and act accordingly if status.code() == Code::AlreadyExists { @@ -157,3 +166,92 @@ pub enum StaleNodeError { tolerance_ms: u64, }, } + +#[cfg(test)] +mod tests { + use super::*; + + mod from_dapi_client_error { + use super::*; + use assert_matches::assert_matches; + use base64::Engine; + use dapi_grpc::tonic::metadata::{MetadataMap, MetadataValue}; + use dpp::consensus::basic::identity::IdentityAssetLockProofLockedTransactionMismatchError; + use dpp::consensus::basic::BasicError; + use dpp::dashcore::hashes::Hash; + use dpp::dashcore::Txid; + use dpp::serialization::PlatformSerializableWithPlatformVersion; + use dpp::version::PlatformVersion; + + #[test] + fn test_already_exists() { + let error = DapiClientError::Transport(TransportError::Grpc( + dapi_grpc::tonic::Status::new(Code::AlreadyExists, "Object already exists"), + )); + + let sdk_error: Error = error.into(); + assert!(matches!(sdk_error, Error::AlreadyExists(_))); + } + + #[test] + fn test_consensus_error() { + let platform_version = PlatformVersion::latest(); + + let consensus_error = ConsensusError::BasicError( + BasicError::IdentityAssetLockProofLockedTransactionMismatchError( + IdentityAssetLockProofLockedTransactionMismatchError::new( + Txid::from_byte_array([0; 32]), + Txid::from_byte_array([1; 32]), + ), + ), + ); + + let consensus_error_bytes = consensus_error + .serialize_to_bytes_with_platform_version(platform_version) + .expect("serialize consensus error to bytes"); + + let mut metadata = MetadataMap::new(); + metadata.insert_bin( + "dash-serialized-consensus-error-bin", + MetadataValue::from_bytes(&consensus_error_bytes), + ); + + let status = + dapi_grpc::tonic::Status::with_metadata(Code::InvalidArgument, "Test", metadata); + + let error = DapiClientError::Transport(TransportError::Grpc(status)); + + let sdk_error = Error::from(error); + + assert_matches!( + sdk_error, + Error::Protocol(ProtocolError::ConsensusError(e)) if matches!(*e, ConsensusError::BasicError( + BasicError::IdentityAssetLockProofLockedTransactionMismatchError(_) + )) + ); + } + + #[test] + fn test_consensus_error_with_fixture() { + let consensus_error_bytes = base64::engine::general_purpose::STANDARD.decode("ATUgJOJEYbuHBqyTeApO/ptxQ8IAw8nm9NbGROu1nyE/kqcgDTlFeUG0R4wwVcbZJMFErL+VSn63SUpP49cequ3fsKw=").expect("decode base64"); + let consensus_error = MetadataValue::from_bytes(&consensus_error_bytes); + + let mut metadata = MetadataMap::new(); + metadata.insert_bin("dash-serialized-consensus-error-bin", consensus_error); + + let status = + dapi_grpc::tonic::Status::with_metadata(Code::InvalidArgument, "Test", metadata); + + let error = DapiClientError::Transport(TransportError::Grpc(status)); + + let sdk_error = Error::from(error); + + assert_matches!( + sdk_error, + Error::Protocol(ProtocolError::ConsensusError(e)) if matches!(*e, ConsensusError::BasicError( + BasicError::IdentityAssetLockProofLockedTransactionMismatchError(_) + )) + ); + } + } +} diff --git a/packages/rs-sdk/src/platform/document_query.rs b/packages/rs-sdk/src/platform/document_query.rs index 1da50d73f86..39ec37d736a 100644 --- a/packages/rs-sdk/src/platform/document_query.rs +++ b/packages/rs-sdk/src/platform/document_query.rs @@ -342,7 +342,7 @@ impl<'a> TryFrom<&'a DocumentQuery> for DriveDocumentQuery<'a> { after.len(), )) })?), - true, + false, ), }; diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index c823df2eae4..64a5db66457 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -10,6 +10,7 @@ use crate::platform::{Fetch, Identifier}; use arc_swap::{ArcSwapAny, ArcSwapOption}; use dapi_grpc::mock::Mockable; use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; +use dapi_grpc::tonic::transport::Certificate; use dpp::bincode; use dpp::bincode::error::DecodeError; use dpp::dashcore::Network; @@ -750,6 +751,9 @@ pub struct SdkBuilder { /// Cancellation token; once cancelled, all pending requests should be aborted. pub(crate) cancel_token: CancellationToken, + + /// CA certificate to use for TLS connections. + ca_certificate: Option, } impl Default for SdkBuilder { @@ -781,6 +785,8 @@ impl Default for SdkBuilder { version: PlatformVersion::latest(), + ca_certificate: None, + #[cfg(feature = "mocks")] dump_dir: None, } @@ -830,6 +836,41 @@ impl SdkBuilder { self } + /// Configure CA certificate to use when verifying TLS connections. + /// + /// Used mainly for testing purposes and local networks. + /// + /// If not set, uses standard system CA certificates. + pub fn with_ca_certificate(mut self, pem_certificate: Certificate) -> Self { + self.ca_certificate = Some(pem_certificate); + self + } + + /// Load CA certificate from file. + /// + /// This is a convenience method that reads the certificate from a file and sets it using + /// [SdkBuilder::with_ca_certificate()]. + pub fn with_ca_certificate_file( + self, + certificate_file_path: impl AsRef, + ) -> std::io::Result { + let pem = std::fs::read(certificate_file_path)?; + + // parse the certificate and check if it's valid + let mut verified_pem = std::io::BufReader::new(pem.as_slice()); + rustls_pemfile::certs(&mut verified_pem) + .next() + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "No valid certificates found in the file", + ) + })??; + + let cert = Certificate::from_pem(pem); + Ok(self.with_ca_certificate(cert)) + } + /// Configure request settings. /// /// Tune request settings used to connect to the Dash Platform. @@ -962,7 +1003,11 @@ impl SdkBuilder { let sdk= match self.addresses { // non-mock mode Some(addresses) => { - let dapi = DapiClient::new(addresses,dapi_client_settings); + let mut dapi = DapiClient::new(addresses, dapi_client_settings); + if let Some(pem) = self.ca_certificate { + dapi = dapi.with_ca_certificate(pem); + } + #[cfg(feature = "mocks")] let dapi = dapi.dump_dir(self.dump_dir.clone()); diff --git a/packages/rs-sdk/tests/.env.example b/packages/rs-sdk/tests/.env.example index f0e4089da66..a731b25f530 100644 --- a/packages/rs-sdk/tests/.env.example +++ b/packages/rs-sdk/tests/.env.example @@ -3,6 +3,7 @@ DASH_SDK_PLATFORM_HOST="127.0.0.1" DASH_SDK_PLATFORM_PORT=2443 DASH_SDK_PLATFORM_SSL=false +# DASH_SDK_PLATFORM_CA_CERT_PATH=/some/path/to/ca.pem # ProTxHash of masternode that has at least 1 vote casted for DPNS name `testname` DASH_SDK_MASTERNODE_OWNER_PRO_REG_TX_HASH="6ac88f64622d9bc0cb79ad0f69657aa9488b213157d20ae0ca371fa5f04fb222" diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index 41d3601cbdf..a93eb2402c5 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -54,6 +54,10 @@ pub struct Config { #[serde(default)] pub platform_ssl: bool, + /// When platform_ssl is true, use the PEM-encoded CA certificate from provided absolute path to verify the server certificate. + #[serde(default)] + pub platform_ca_cert_path: Option, + /// Directory where all generated test vectors will be saved. /// /// See [SdkBuilder::with_dump_dir()](crate::SdkBuilder::with_dump_dir()) for more details. @@ -193,7 +197,11 @@ impl Config { &self.core_user, &self.core_password, ); - + if let Some(cert_file) = &self.platform_ca_cert_path { + builder = builder + .with_ca_certificate_file(cert_file) + .expect("load CA cert"); + } #[cfg(feature = "generate-test-vectors")] let builder = { // When we use namespaces, clean up the namespaced dump dir before starting diff --git a/packages/rs-sdk/tests/fetch/data_contract.rs b/packages/rs-sdk/tests/fetch/data_contract.rs index 41ef33138e9..b6d47cdd5f0 100644 --- a/packages/rs-sdk/tests/fetch/data_contract.rs +++ b/packages/rs-sdk/tests/fetch/data_contract.rs @@ -8,6 +8,8 @@ use drive_proof_verifier::types::DataContractHistory; /// Given some dummy data contract ID, when I fetch data contract, I get None because it doesn't exist. #[tokio::test(flavor = "multi_thread", worker_threads = 1)] async fn test_data_contract_read_not_found() { + super::common::setup_logs(); + pub const DATA_CONTRACT_ID_BYTES: [u8; 32] = [1; 32]; let id = Identifier::from_bytes(&DATA_CONTRACT_ID_BYTES).expect("parse identity id"); diff --git a/packages/simple-signer/Cargo.toml b/packages/simple-signer/Cargo.toml index a6802352c21..f6a91dc988d 100644 --- a/packages/simple-signer/Cargo.toml +++ b/packages/simple-signer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simple-signer" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true @@ -8,6 +8,6 @@ rust-version.workspace = true [dependencies] bincode = { version = "2.0.0-rc.3", features = ["serde"] } -dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.15.13" } +dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.16.0" } dpp = { path = "../rs-dpp", features = ["abci"] } base64 = { version = "0.22.1" } diff --git a/packages/strategy-tests/Cargo.toml b/packages/strategy-tests/Cargo.toml index c445290ecca..f7fa7e815ce 100644 --- a/packages/strategy-tests/Cargo.toml +++ b/packages/strategy-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "strategy-tests" -version = "1.7.0" +version = "1.8.0" authors = [ "Samuel Westrich ", "Ivan Shumkov ", @@ -46,4 +46,4 @@ platform-version = { path = "../rs-platform-version", features = [ ] } # For tests of grovedb verify -rocksdb = { version = "0.22.0" } +rocksdb = { version = "0.23.0" } diff --git a/packages/wallet-lib/package.json b/packages/wallet-lib/package.json index f258d9678de..77f762556f2 100644 --- a/packages/wallet-lib/package.json +++ b/packages/wallet-lib/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wallet-lib", - "version": "8.7.0", + "version": "8.8.0", "description": "Light wallet library for Dash", "main": "src/index.js", "unpkg": "dist/wallet-lib.min.js", diff --git a/packages/wallet-utils-contract/Cargo.toml b/packages/wallet-utils-contract/Cargo.toml index 7e2527e7a2a..8cf721548c1 100644 --- a/packages/wallet-utils-contract/Cargo.toml +++ b/packages/wallet-utils-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "wallet-utils-contract" description = "Wallet data contract schema and tools" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/wallet-utils-contract/package.json b/packages/wallet-utils-contract/package.json index 621f0c05efd..c2bab2523db 100644 --- a/packages/wallet-utils-contract/package.json +++ b/packages/wallet-utils-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wallet-utils-contract", - "version": "1.7.0", + "version": "1.8.0", "description": "A contract and helper scripts for Wallet DApp", "scripts": { "lint": "eslint .", diff --git a/packages/wasm-dpp/Cargo.toml b/packages/wasm-dpp/Cargo.toml index 2b34c8af6ff..d7575a859ce 100644 --- a/packages/wasm-dpp/Cargo.toml +++ b/packages/wasm-dpp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-dpp" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true authors = ["Anton Suprunchuk "] @@ -15,7 +15,7 @@ serde_json = { version = "1.0", features = ["preserve_order"] } # Meantime if you want to update wasm-bindgen you also need to update version in: # - packages/wasm-dpp/scripts/build-wasm.sh # - Dockerfile -wasm-bindgen = { version = "=0.2.86" } +wasm-bindgen = { version = "=0.2.99" } js-sys = "0.3.53" web-sys = { version = "0.3.6", features = ["console"] } thiserror = { version = "1.0.63" } @@ -49,11 +49,11 @@ hex = { version = "0.4" } paste = "1.0.14" anyhow = { version = "1.0.75" } # required, cargo-machete false positive -wasm-bindgen-futures = "0.4.33" +wasm-bindgen-futures = "0.4.49" async-trait = "0.1.59" bincode = "2.0.0-rc.3" [profile.release] lto = true -opt-level = 's' +opt-level = 'z' [package.metadata.cargo-machete] ignored = ["wasm-bindgen-futures"] diff --git a/packages/wasm-dpp/README.md b/packages/wasm-dpp/README.md index 73b3494c454..e16390f30ad 100644 --- a/packages/wasm-dpp/README.md +++ b/packages/wasm-dpp/README.md @@ -39,7 +39,7 @@ Library consumers must ignore class names minification for `@dashevo/wasm-dpp` l - Install [Rust](https://www.rust-lang.org/tools/install) v1.73+ - Add wasm32 target: `$ rustup target add wasm32-unknown-unknown` -- Install wasm-bingen-cli: `cargo install wasm-bindgen-cli@0.2.86` +- Install wasm-bingen-cli: `cargo install wasm-bindgen-cli@0.2.99` - *double-check that wasm-bindgen-cli version above matches wasm-bindgen version in Cargo.lock file* - *Depending on system, additional packages may need to be installed as a prerequisite for wasm-bindgen-cli. If anything is missing, installation will error and prompt what packages are missing (i.e. clang, llvm, libssl-dev)* diff --git a/packages/wasm-dpp/lib/index.ts b/packages/wasm-dpp/lib/index.ts index 8027f069bed..b4031ee4144 100644 --- a/packages/wasm-dpp/lib/index.ts +++ b/packages/wasm-dpp/lib/index.ts @@ -35,7 +35,7 @@ const loadDppModule = async () => { let wasmUrl = URL.createObjectURL(blob); await init(wasmUrl); } else { - dpp_module.initSync(bytes); + dpp_module.initSync({ module: bytes }); } } diff --git a/packages/wasm-dpp/package.json b/packages/wasm-dpp/package.json index ca3b0ca9182..26db1957ae5 100644 --- a/packages/wasm-dpp/package.json +++ b/packages/wasm-dpp/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/wasm-dpp", - "version": "1.7.0", + "version": "1.8.0", "description": "The JavaScript implementation of the Dash Platform Protocol", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/wasm-dpp/scripts/build-wasm.sh b/packages/wasm-dpp/scripts/build-wasm.sh index 0c154372bae..b7ada5425ef 100755 --- a/packages/wasm-dpp/scripts/build-wasm.sh +++ b/packages/wasm-dpp/scripts/build-wasm.sh @@ -47,8 +47,9 @@ fi # EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry" cargo build --target=wasm32-unknown-emscripten --release # EMCC_CFLAGS="-s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry" wasm-bindgen --out-dir=wasm --target=web --omit-default-module-path ../../target/wasm32-unknown-emscripten/release/wasm_dpp.wasm -# TODO: Must be somehow preinstalled? -#if [ "$PROFILE" == "release" ]; then -# echo "Optimizing wasm using Binaryen" -# wasm-opt -Os "$OUTPUT_FILE" -o "$OUTPUT_FILE" -#fi +if command -v wasm-opt &> /dev/null; then + echo "Optimizing wasm using Binaryen" + wasm-opt -Oz "$OUTPUT_FILE" -o "$OUTPUT_FILE" +else + echo "wasm-opt command not found. Skipping wasm optimization." +fi diff --git a/packages/wasm-dpp/src/identity/factory_utils.rs b/packages/wasm-dpp/src/identity/factory_utils.rs index 18e19428423..f14431ac8ee 100644 --- a/packages/wasm-dpp/src/identity/factory_utils.rs +++ b/packages/wasm-dpp/src/identity/factory_utils.rs @@ -9,7 +9,6 @@ use dpp::identity::{IdentityPublicKey, KeyID}; use dpp::serialization::ValueConvertible; use dpp::state_transition::public_key_in_creation::IdentityPublicKeyInCreation; use std::collections::BTreeMap; -use wasm_bindgen::__rt::Ref; use wasm_bindgen::{JsCast, JsValue}; pub fn parse_public_keys( @@ -47,11 +46,10 @@ pub fn parse_create_identity_update_transition_keys( let keys: Vec = add_public_keys_array .iter() .map(|key| { - let public_key: Ref = - generic_of_js_val::( - &key, - "IdentityPublicKeyWithWitness", - )?; + let public_key = generic_of_js_val::( + &key, + "IdentityPublicKeyWithWitness", + )?; Ok(public_key.clone().into()) }) @@ -74,7 +72,7 @@ pub fn parse_create_identity_update_transition_keys( let keys: Vec = disable_public_keys_array .iter() .map(|key| { - let public_key_wasm: Ref = + let public_key_wasm = generic_of_js_val::(&key, "IdentityPublicKey")?; Ok(public_key_wasm.get_id()) }) diff --git a/packages/wasm-dpp/src/identity/state_transition/asset_lock_proof/mod.rs b/packages/wasm-dpp/src/identity/state_transition/asset_lock_proof/mod.rs index 861188d0ca4..dd4fca03cd3 100644 --- a/packages/wasm-dpp/src/identity/state_transition/asset_lock_proof/mod.rs +++ b/packages/wasm-dpp/src/identity/state_transition/asset_lock_proof/mod.rs @@ -5,7 +5,6 @@ pub use chain::*; pub use instant::*; use std::convert::TryInto; use wasm_bindgen::JsCast; -use wasm_bindgen::__rt::Ref; use dpp::identity::errors::UnknownAssetLockProofTypeError; use wasm_bindgen::prelude::*; @@ -144,13 +143,13 @@ pub fn create_asset_lock_proof_from_wasm_instance( match lock_type { AssetLockProofType::Instant => { - let instant: Ref = + let instant = generic_of_js_val::(js_value, "InstantAssetLockProof")?; Ok(AssetLockProof::Instant(instant.clone().into())) } AssetLockProofType::Chain => { - let chain: Ref = + let chain = generic_of_js_val::(js_value, "ChainAssetLockProof")?; Ok(AssetLockProof::Chain(chain.clone().into())) diff --git a/packages/wasm-dpp/src/identity/state_transition/identity_create_transition/identity_create_transition.rs b/packages/wasm-dpp/src/identity/state_transition/identity_create_transition/identity_create_transition.rs index 86681592df3..9b5a402ddd2 100644 --- a/packages/wasm-dpp/src/identity/state_transition/identity_create_transition/identity_create_transition.rs +++ b/packages/wasm-dpp/src/identity/state_transition/identity_create_transition/identity_create_transition.rs @@ -1,6 +1,5 @@ use std::default::Default; -use wasm_bindgen::__rt::Ref; use wasm_bindgen::prelude::*; use crate::bls_adapter::BlsAdapter; @@ -101,11 +100,10 @@ impl IdentityCreateTransitionWasm { let public_keys = public_keys .iter() .map(|value| { - let public_key: Ref = - generic_of_js_val::( - value, - "IdentityPublicKeyWithWitness", - )?; + let public_key = generic_of_js_val::( + value, + "IdentityPublicKeyWithWitness", + )?; Ok(public_key.clone().into()) }) .collect::, JsValue>>()?; @@ -120,11 +118,10 @@ impl IdentityCreateTransitionWasm { let mut public_keys = public_keys .iter() .map(|value| { - let public_key: Ref = - generic_of_js_val::( - value, - "IdentityPublicKeyWithWitness", - )?; + let public_key = generic_of_js_val::( + value, + "IdentityPublicKeyWithWitness", + )?; Ok(public_key.clone().into()) }) .collect::, JsValue>>()?; diff --git a/packages/wasm-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs b/packages/wasm-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs index 1d8988ba6f9..5692dd63d3f 100644 --- a/packages/wasm-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs +++ b/packages/wasm-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs @@ -1,24 +1,12 @@ -use std::convert::TryInto; -use std::default::Default; - -use serde::{Deserialize, Serialize}; - -use wasm_bindgen::__rt::Ref; -use wasm_bindgen::prelude::*; - +use crate::bls_adapter::{BlsAdapter, JsBlsAdapter}; +use crate::errors::from_dpp_err; use crate::identifier::IdentifierWrapper; - +use crate::utils::{generic_of_js_val, WithJsError}; use crate::{ buffer::Buffer, identity::state_transition::identity_public_key_transitions::IdentityPublicKeyWithWitnessWasm, identity::IdentityPublicKeyWasm, with_js_error, }; - -use crate::bls_adapter::{BlsAdapter, JsBlsAdapter}; - -use crate::utils::{generic_of_js_val, WithJsError}; - -use crate::errors::from_dpp_err; use dpp::errors::consensus::signature::SignatureError; use dpp::errors::consensus::ConsensusError; use dpp::errors::ProtocolError; @@ -34,6 +22,10 @@ use dpp::state_transition::StateTransition; use dpp::state_transition::StateTransitionIdentitySigned; use dpp::version::PlatformVersion; use dpp::{identifier::Identifier, state_transition::StateTransitionLike}; +use serde::{Deserialize, Serialize}; +use std::convert::TryInto; +use std::default::Default; +use wasm_bindgen::prelude::*; #[wasm_bindgen(js_name=IdentityUpdateTransition)] #[derive(Clone)] @@ -93,11 +85,10 @@ impl IdentityUpdateTransitionWasm { keys_to_add = keys .iter() .map(|value| { - let public_key: Ref = - generic_of_js_val::( - value, - "IdentityPublicKeyWithWitness", - )?; + let public_key = generic_of_js_val::( + value, + "IdentityPublicKeyWithWitness", + )?; Ok(public_key.clone().into()) }) .collect::, JsValue>>()?; diff --git a/packages/withdrawals-contract/Cargo.toml b/packages/withdrawals-contract/Cargo.toml index 21f474d5e5b..bb4b612765e 100644 --- a/packages/withdrawals-contract/Cargo.toml +++ b/packages/withdrawals-contract/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "withdrawals-contract" description = "Witdrawals data contract schema and tools" -version = "1.7.0" +version = "1.8.0" edition = "2021" rust-version.workspace = true license = "MIT" diff --git a/packages/withdrawals-contract/package.json b/packages/withdrawals-contract/package.json index d49ca9d113c..5e9d1ac2e66 100644 --- a/packages/withdrawals-contract/package.json +++ b/packages/withdrawals-contract/package.json @@ -1,6 +1,6 @@ { "name": "@dashevo/withdrawals-contract", - "version": "1.7.0", + "version": "1.8.0", "description": "Data Contract to manipulate and track withdrawals", "scripts": { "build": "", diff --git a/scripts/configure_test_suite_network.sh b/scripts/configure_test_suite_network.sh index 498e9d2d03e..b84e0286afa 100755 --- a/scripts/configure_test_suite_network.sh +++ b/scripts/configure_test_suite_network.sh @@ -57,16 +57,15 @@ MASTERNODE_OWNER_MASTER_PRIVATE_KEY=$(yq .hp_masternodes."$MASTERNODE_NAME".owne if [[ "$NETWORK_STRING" == "devnet"* ]]; then NETWORK=devnet - INSIGHT_URL="http://insight.${NETWORK_STRING#devnet-}.networks.dash.org:3001/insight-api/sync" CERT_FLAG=":self-signed" ST_EXECUTION_INTERVAL=5000 else NETWORK=testnet - INSIGHT_URL="https://testnet-insight.dashevo.org/insight-api/sync" CERT_FLAG="" ST_EXECUTION_INTERVAL=15000 fi -SKIP_SYNC_BEFORE_HEIGHT=4800 # $(curl -s $INSIGHT_URL | jq '.height - 200') +INSIGHT_URL="http://insight.${NETWORK_STRING#devnet-}.networks.dash.org:3001/insight-api/sync" +SKIP_SYNC_BEFORE_HEIGHT=$(curl -s $INSIGHT_URL | jq '.height - 200') # check variables are not empty if [ -z "$FAUCET_ADDRESS" ] || \ diff --git a/yarn.lock b/yarn.lock index 0119fa898d7..e4829725aa1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6471,7 +6471,7 @@ __metadata: semver: "npm:^7.5.3" sinon: "npm:^17.0.1" sinon-chai: "npm:^3.7.0" - systeminformation: "npm:^5.22.11" + systeminformation: "npm:^5.25.11" table: "npm:^6.8.1" tar: "npm:7.4.3" wrap-ansi: "npm:^7.0.0" @@ -14695,12 +14695,12 @@ __metadata: languageName: node linkType: hard -"systeminformation@npm:^5.22.11": - version: 5.22.11 - resolution: "systeminformation@npm:5.22.11" +"systeminformation@npm:^5.25.11": + version: 5.25.11 + resolution: "systeminformation@npm:5.25.11" bin: systeminformation: lib/cli.js - checksum: 315cd3f2cc2aefbee9201fac043521d073e8c94a77f8900617dad67fdb798116fd2963a365d4d3da81dbca6da360d1f7008c61e1fe33ef9f8f3b77aa4f506014 + checksum: 9a43bb8991ac07a0bcf3f9002c32e9f36a1100b2f620049c4c3dc24f74556c681b1e4552dc27581af32a842540cd42c1bb085e842b0c325273fb558b51c7159f conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android) languageName: node linkType: hard